<?php //====================================================================================== // // Function: Main menu for GPS // // Programmer: AR // Date : 2024-10-08 // // Copyright Reeft A/S (c) - 2024 //====================================================================================== header("Access-Control-Allow-Origin: *"); // Or specify a specific origin header("Access-Control-Allow-Methods: POST, GET, OPTIONS"); header("Access-Control-Allow-Headers: Content-Type, Authorization"); // Handle preflight requests if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } //====================================================================================== // Set session //====================================================================================== if(!isset($_SESSION)) { session_start(); } //====================================================================================== // General //====================================================================================== include "include/apikey.php"; include "include/config.php"; // Check if the token is already in the session if (!isset($_SESSION['TargetOrganization']) || !isset($_REQUEST['TargetOrganization']) || $_SESSION['TargetOrganization'] != $_REQUEST['TargetOrganization']) { // Include the token validation include_once "token_validation.php"; } //====================================================================================== // Language data ["en", "de", "da", "no", "sv"] //====================================================================================== $loginLanguage = $_SESSION['loginLanguage']; include "language/$loginLanguage.php"; ?> <!DOCTYPE html> <html lang="en"> <head> <title>GPS</title> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content="REEFT GPS"> <meta name="author" content="REEFT A/S"> <link rel="icon" href="images/favicon/favicon.ico"> <link href="javascript/bootstrap-5.3.3/css/bootstrap.min.css" rel="stylesheet"> <link href="javascript/chosen_v1.8.7/chosen.css" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="javascript/jquery-ui-1.14.1/jquery-ui.css"> <link href="javascript/fontawesome/6.5.1/css/all.min.css" rel="stylesheet" type="text/css"> <link href="javascript/fontawesome/6.5.1/css/sharp-solid.min.css" rel="stylesheet" type="text/css"> <link href="css/sticky-footer.css" rel="stylesheet" type="text/css"> <script src="javascript/jquery-3.7.1.min.js"></script> <script src="javascript/jquery-ui-1.14.1/jquery-ui.min.js"></script> <script src="javascript/popper.min.js"></script> <script src="javascript/ajaxq/ajaxq.js"></script> <script src="javascript/bootstrap-5.3.3/js/bootstrap.min.js"></script> <script src="javascript/chosen_v1.8.7/chosen.jquery.min.js" type="text/javascript"></script> <script type="text/javascript" src="javascript/markerclusterer.min.js"></script> <script type="text/javascript" src="javascript/infobubble.js"></script> <script type="text/javascript" src="javascript/xlxs-0.15.6/xlsx.full.min.js"></script> <link href="css/main.css" rel="stylesheet"> <!-- Loads the Google Maps API script asynchronously, the script runs only after the HTML document has been fully parsed --> <script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&key=<?php echo $apikey; ?>&callback=initMap&v=<?php echo time(); ?>" async defer></script> <script language="JavaScript"> //============================================================================= // Globals //============================================================================= //variables from REEFT 2.0 var token = '<?php echo $_SESSION['token']; ?>'; var loginOrganizationId = '<?php echo $_SESSION['loginOrganizationId']; ?>'; var loginOrganizationName = '<?php echo $_SESSION['loginOrganizationName']; ?>'; var loginUserId = '<?php echo $_SESSION['loginUserId']; ?>'; var loginUserName = '<?php echo $_SESSION['loginUserName']; ?>'; var loginUserRole = '<?php echo $_SESSION['loginUserRole']; ?>'; var loginDepartmentId = '<?php echo $_SESSION['loginDepartmentId']; ?>'; var loginDepartmentName = '<?php echo $_SESSION['loginDepartmentName']; ?>'; var dftMapCenterLat = <?php echo $DFT_MAP_CENTER_LAT; ?>; var dftMapCenterLng = <?php echo $DFT_MAP_CENTER_LNG; ?>; var dftZoomlevel = <?php echo $DFT_ZOOMLEVEL; ?>; var gsmKey = '<?php echo $gsmKey; ?>'; var onlineLegend = '<?php echo $locale_text["GPSMAP_online_legend"]; ?>'; var yellowLegend = '<?php echo $locale_text["GPSMAP_yellow_legend"]; ?>'; var offlineLegend = '<?php echo $locale_text["GPSMAP_offline_legend"]; ?>'; var imeiList = []; var carData = []; var empJobList = []; var jobtooltip = $("<div id='tooltip'><div class='mousehovercontent'/></div>"); var toolTipTimer = ""; var haveTooltip = false; var custPopoverVisible = false; // Tracks the visibility of the popover var jobPopoverVisible = false; // Tracks the visibility of the popover var lastUpdated = Date.now(); // Last provided UNIX timestamp to getlocations var inputTimer; var lastSearchString = ""; var custQueueCount = 0; var excelData = []; // Variable to store data to export to excel var excelKeys = {}; // keys to lockup in excelData var mapGlobals = {}; mapGlobals.map; // Google map obj. mapGlobals.markerCluster; // Google map marker cluster mapGlobals.infoBubble ; // InfoBubble at cluster mapGlobals.allMarkers = {}; // Contains a list to store all markers mapGlobals.infoWin; // Google infowindow object, reused for all info windows mapGlobals.JSON_employeeList; // Contains a list of employees mapGlobals.JSON_gpsTransactions; // Contains GPS transaction (latlng) for an employee mapGlobals.JSON_customerList; // Contains a list of customers that have been requested through customer search. mapGlobals.JSON_customerListID = new Array(); // Contains a list of id for customers mapGlobals.JSON_serviceUnitID = new Array(); // Contains a list of id for serviceunits mapGlobals.JSON_locationList = {}; // Contains a list of car locations mapGlobals.JSON_jobList = {}; // Contains a list of jobs locations mapGlobals.gpsEmployeeMarkersArray = new Array(); // Contains employee markers that are displayed mapGlobals.addressMarker; // Contains marker object from address search mapGlobals.gpsEmpLocationMarkers = new Array(); // Contains locations markers for an employee mapGlobals.custSearching = false; // Determines if a cutomer search is in progress, used for controling enter key press behaviour mapGlobals.currentCustomerMarker; // Selected customer marker obj mapGlobals.selectedCustomer = ""; // Selected customer in customer section mapGlobals.selectedJobs = new Array(); // Contains job selected in list. mapGlobals.selectedMachines = new Array(); // Contains machines selected in list. mapGlobals.selectedEmployees = new Array(); // Contains employees selected in list. Used for keeping state when refreshing map. mapGlobals.routePolyline; // Polyline object for a route mapGlobals.routeArray; // Contains routes const jobStatusText = <?php echo json_encode($locale_text["JOB_STATUS"]); ?>; const timesheetText = <?php echo json_encode($locale_text["TIMESHEET_STATUS"]); ?>; var hoverTimeout; //get initial data from REEFT 2.0 getEmeiList(); getEmployeeList(); getDepartmentList(); //============================================================================= // Get a JSON list of employees with emei //============================================================================= function getEmeiList(){ $.ajaxq('getQueue',{ cache: false, url: "ajax_get_emei_list.php", dataType: "json", success: function(jsonData){ //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; imeiList = Object.keys(jsonData); mapGlobals.JSON_employeeList = jsonData; var resultHTMLEmp = ""; $.each( jsonData, function( index, item ){ const id = item.id; const userId = item.userId; const depName = item.departmentName; const depCode = item.departmentCode; const depId = item.departmentId; const imei = item.imei; const name = item.name; const initials = item.initials; resultHTMLEmp += "<li id=\"emp_"+imei+"\" class=\"list-group-item d-flex justify-content-between align-items-center listItem dep_"+depId+" isOffline d-none\" style=\"font-size: 0.9rem !important;\">("+initials+") "+name+"<span class=\"list-right d-flex align-items-center\"><span id=\"empInfo_"+imei+"\" class=\"listIconInfo me-2\"><i class=\"fa-solid fa-circle-info\"></i></span><span class=\"badge bg-danger border border-light rounded-circle\" title=\""+offlineLegend+"\">&nbsp;</span></span></li>"; }); // employees $("#employeeList").html(resultHTMLEmp); // Add click event to listIconInfo $('#employeeList .listIconInfo').on('click', function () { event.stopPropagation(); // Get the clicked icon's position const icon = $(this); // Customize modal content dynamically based on the clicked element const employeeId = $(this).closest('li').attr('id'); const persID = employeeId.split("_"); const imei = persID[1]; const emp = mapGlobals.JSON_employeeList[imei]; const location = mapGlobals.JSON_locationList[imei]; const id = emp.id; const userId = emp.userId; const name = emp.name; const initials = emp.initials; const phone = emp.phone; if (typeof location !== "undefined" && location !== null) { var deviceId = location.id; var lat = location.lat; var lng = location.lng; } const addressId = 'addressTxt_'+imei; var labelHTML = '<div class="row">' + '<div id="selectedEmp" class="col">' + '(' + initials + ') ' + name ; if (phone != "" && phone != "null") { labelHTML += '&nbsp;&nbsp;' + '<i class="fa-light fa-phone"></i> ' + phone ; } labelHTML += '</div>' + '</div>'; labelHTML += '<div class="row">' + '<div class="col">' + '<span id="'+addressId+'"></span>' + '</div>' + '</div>'; $('#empInfoModalLabel').html(labelHTML); $('#empInfoModal-userId').val(userId); $("#day-gpsContainer").html(""); $("#period-gpsContainer").html(""); if (typeof location !== "undefined" && location !== null) { geoCodeLatLng(lat, lng, addressId); $("#empInfoModal-deviceId").val(deviceId); } else { const errmsg = '<?php echo $locale_text["GPSMAP_unknown_location"] ?>'; $("#"+addressId).html(errmsg); $("#empInfoModal-deviceId").val(""); } $("#empInfoModal").draggable({ handle: ".modal-header", scroll: false // Prevent draggable from affecting scrolling }); const nodata = '<?php echo $locale_text["GPSMAP_noData"] ?>'; //TODO: get data getJobs(userId , "#empTodayJobContainer"); // Reset $("#hideRouteBtn").click(); $("#hideRouteBtn").addClass("d-none"); $("#showRouteBtn").removeClass("d-none"); // Prevent scroll from getting dragged along $('#empInfoModal-body').on('mousedown touchstart', function (e) { e.stopPropagation(); // Stop propagation to the draggable modal }); // Show the modal const modal = new bootstrap.Modal(document.getElementById('empInfoModal'), { backdrop: false // Disable backdrop interference }); modal.show(); //document.getElementById('offcanvasScrolling').classList.add('show'); }); } } }); } //============================================================================= // Get a JSON list of department //============================================================================= function getDepartmentList(){ $.ajaxq('getQueue',{ cache: false, url: "ajax_get_department_list.php", dataType: "json", success: function(jsonData){ //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; //get departments var resultHTMLDep = ""; $.each( jsonData, function( index, item ){ const id = item.id; const name = item.name; const userCount = item.userCount; resultHTMLDep += "<option value=\""+id+"\">"+name+"</option>"; }); // departments $("#depListDropDown").html(resultHTMLDep); $("#depListDropDown").chosen({width: "100%"}); $("#jobDepListDropDown").html(resultHTMLDep); $("#jobDepListDropDown").chosen({width: "100%"}); $("#jobCreateDepListDropDown").html("<option value=\"\"></option>" + resultHTMLDep); $("#jobCreateDepListDropDown").chosen({width: "100%", allow_single_deselect: true}); } } }); } //============================================================================= // Get a JSON list of employees //============================================================================= function getEmployeeList(){ $.ajaxq('getQueue',{ cache: false, url: "ajax_get_employee_list.php", dataType: "json", success: function(jsonData){ //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; var resultHTMLEmp = ""; $.each( jsonData, function( index, item ){ const id = item.id; const userId = item.userId; const depName = item.departmentName; var depId = item.departmentId ; const orgName = item.organizationName; const orgId = item.organizationId ; const imei = item.imei; const name = item.name; const initials = item.initials; if (!depId || depId == "") depId = orgId; resultHTMLEmp += "<option value=\""+userId+"\" class=\"dep_"+depId+" \">("+initials+") "+name+"</option>"; }); // employees $("#jobEmpListDropDown").html(resultHTMLEmp); $("#jobEmpListDropDown").chosen({width: "100%"}); $("#jobCreateEmpListDropDown").html("<option class=\"allDep\" value=\"\"></option>" + resultHTMLEmp); $("#jobCreateEmpListDropDown").chosen({width: "100%"}); } } }); } //============================================================================= // Create job //============================================================================= function jobCreate(customer){ const id = customer.id; const name = customer.name; const label = '<?php echo $locale_text["GPSMAP_create_job"] ?>'; var labelHTML = label + " <span class=\"fw-bold\">" + name + "</span>"; const form = document.getElementById("jobCreateForm"); form.reset(); // Clear all inputs, selects, and textareas $("#jobCreateDepListDropDown").val("").trigger("chosen:updated"); // Reset dropdown $("#jobCreateActTypeListDropDown").val("").trigger("chosen:updated"); // Reset dropdown $("#jobCreateEmpListDropDown").val("").trigger("chosen:updated"); // Reset dropdown $('#jobCreateModalLabel').html(labelHTML); $('#jobCreateModal-custId').val(id); $('#jobCreateModal-serviceunitId').val(''); // Show the modal const modal = new bootstrap.Modal(document.getElementById('jobCreateModal'), { backdrop: false // Disable backdrop interference }); modal.show(); } //============================================================================= // Create job serviceunit //============================================================================= function jobCreateServiceunit(serviceunitID, serviceunitName){ if(mapGlobals.selectedCustomer != ""){ jobCreate(mapGlobals.selectedCustomer, "CUST"); } else{ alert("<?php echo $locale_text["ERROR_CHOOSE_CUST"]; ?>"); } var customer = mapGlobals.selectedCustomer; const id = customer.id; const name = customer.name; const label = '<?php echo $locale_text["GPSMAP_create_job"] ?>'; var labelHTML = label + " <span class=\"fw-bold\">" + name + " / " + serviceunitName + "</span>"; const form = document.getElementById("jobCreateForm"); form.reset(); // Clear all inputs, selects, and textareas $("#jobCreateDepListDropDown").val("").trigger("chosen:updated"); // Reset dropdown $("#jobCreateActTypeListDropDown").val("").trigger("chosen:updated"); // Reset dropdown $("#jobCreateEmpListDropDown").val("").trigger("chosen:updated"); // Reset dropdown $('#jobCreateModalLabel').html(labelHTML); $('#jobCreateModal-custId').val(id); $('#jobCreateModal-serviceunitId').val(serviceunitID); // Show the modal const modal = new bootstrap.Modal(document.getElementById('jobCreateModal'), { backdrop: false // Disable backdrop interference }); modal.show(); } //============================================================================= // Clear jobliste //============================================================================= function clearJoblist(){ // Hide all jobs $("#hideAllJobsBtn").click(); $("#mainJobList").html(""); $("#clearAllJobsBtn").addClass("d-none"); $("#showAllJobsBtn").addClass("d-none"); } //============================================================================= // Get jobliste //============================================================================= function getJoblist(){ $("#job-message").addClass("d-none"); // Hide all jobs $("#hideAllJobsBtn").click(); const fromDate = $('#job-fromdateInput').val(); const toDate = $('#job-todateInput').val(); const selectedDep = $('#jobDepListDropDown').val(); var selectedEmp = $('#jobEmpListDropDown').val(); const selectedStatus = $('#jobStatusListDropDown').val(); const selectedActType = $('#jobActTypeListDropDown').val(); const jobGetUnassigned = $('#jobGetUnassigned').prop('checked'); const getUnassigned = (jobGetUnassigned ? 'Y' : 'N'); if (selectedEmp.length == 0 && selectedDep.length > 0) { // Filter out the disabled options var allOptions = $('#jobEmpListDropDown option'); var nonDisabledOptions = allOptions.filter(function () { return !$(this).is(':disabled'); }); let nonDisabledValues = nonDisabledOptions.map(function () { return $(this).val(); }).get(); selectedEmp = nonDisabledValues; } if (fromDate.trim() == "") { $("#job-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_FROMDATE_WARNING"] ?>' ); $('#job-fromdateInput').focus(); return; } if (toDate.trim() == "") { $("job-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_TODATE_WARNING"] ?>' ); $('#job-todateInput').focus(); return; } if (toDate < fromDate) { $("#job-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_DATE_GREATER"] ?>' ); $('#job-todateInput').focus(); return; } parmData = 'selectedDep='+selectedDep + '&selectedEmp='+selectedEmp + '&selectedStatus='+selectedStatus + '&selectedActType='+selectedActType + '&startDate=' + fromDate + '&endDate=' + toDate + '&getUnassigned=' + getUnassigned + '&type=**LIST**' ; $("#jobListSpinner").removeClass("d-none"); $.ajax({ cache: false, url: "ajax_get_joblist.php", data: parmData, dataType: "json", success: function(jsonData){ //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; const jobList = jsonData["jobList"]; const jobscheduleList = jsonData["jobscheduleList"]; var resultCount = Object.keys(jobList).length; if ( resultCount == 0 ) { var resultHTML = "<?php echo $locale_text["GPSMAP_noData"]; ?>" } else { var resultHTML = ""; $("#showAllJobsBtn").removeClass("d-none"); $("#clearAllJobsBtn").removeClass("d-none"); } $.each( jobList, function( index, item ){ empJobList[item["jobNumber"]] = item; const id = item["id"]; const jobNumber = item["jobNumber"]; const externalJobNumber = item["externalJobNumber"]; const jobTagName = item["jobTagName"]; const activityTypeName = item["activityTypeName"]; const customerName = item["customerName"]; const responsibleName = item["responsibleName"]; const createdByName = item["createdByName"]; const isGroup = item["isGroup"]; const departmentName = item["departmentName"]; const customerCode = item["customerCode"]; const customerCategory = item["customerCategory"]; const serviceUnitCode = item["serviceUnitCode"]; const serviceUnitName = item["serviceUnitName"]; const serviceUnitSerialNumber = item["serviceUnitSerialNumber"]; const serviceUnitCategory = item["serviceUnitCategory"]; const assignedTo = item["assignedTo"]; const completedDateTime = item["completedDateTime"]; const totalScheduledWork = item["totalScheduledWork"]; const totalTimeLogged = item["totalTimeLogged"]; const clientDateTime = item["clientDateTime"]; const isRecurring = item["isRecurring"]; const isCritical = item["isCritical"]; const jobStatus = item["jobStatus"]; const contactPerson = item["contactPerson"]; const contactPhone = item["contactPhone"]; const contactEmail = item["contactEmail"]; const contactMobile = item["contactMobile"]; const shortDescription = item["shortDescription"]; const requisitionNumber = item["requisitionNumber"]; const estimatedHours = item["estimatedHours"]; const startDateTime = item["startDateTime"]; const startDateTimeLocal = item["startDateTimeLocal"]; const dueDateTime = item["dueDateTime"]; const dueDateTimeLocal = item["dueDateTimeLocal"]; const location = item["location"]; const street = item["street"]; const zipCode = item["zipCode"]; const city = item["city"]; const country = item["country"]; const longitude = item["longitude"]; const latitude = item["latitude"]; const createdAt = item["createdAt"]; const createdDateTime = item["createdDateTime"]; mapGlobals.JSON_jobList[jobNumber] = item; var jobStatusTxt = jobStatusText[jobStatus]; var address = item["location"] + " " + item["street"] + " " + item["zipCode"] + " " + item["city"]+ " " + item["country"] ; address = address.replace("null", "").trim(); mapGlobals.JSON_jobList[jobNumber]["address"] = address; resultHTML += "<li id=\"job_"+jobNumber+"\" class=\"list-group-item listItem jobListItem text-break text-wrap\"><span class=\"d-flex justify-content-between align-items-center\">("+jobNumber+") "+shortDescription+"<span class=\"list-right d-flex align-items-center\"><span id=\"jobInfo_"+jobNumber+"\" class=\"listIconInfo jobSearchIcon me-2\"><i class=\"fa-solid fa-circle-info\"></i></span></span></span><span>"+address+"</span></li>"; }); $("#jobListSpinner").addClass("d-none"); $("#mainJobList").html(resultHTML); // Add click event to listIconInfo $("#mainJobList").on("mouseenter", ".listIconInfo", function () { const $icon = $(this); // Clear any existing timeout to avoid multiple triggers clearTimeout(hoverTimeout); // Check if the popover is already visible for the current icon if ($icon.attr("aria-describedby")) { return; // Popover is already shown; do nothing } // Dispose of any existing popover to prevent duplicates $(".jobSearchIcon").not($icon).each(function() { $(this).popover("dispose"); }); hoverTimeout = setTimeout(() => { var jobID = $(this).attr("id").split("_"); jobID = jobID[1]; const jobUuid = empJobList[jobID]["id"] parmData = 'jobUuid='+jobUuid ; $.ajax({ cache: false, url: "ajax_get_jobdetail.php", data: parmData, dataType: "json", success: function(jsonDataDetail){ //console.log(jsonDataDetail); if (jsonDataDetail["error"] != "") { console.log(jsonDataDetail["error"]); } else { delete jsonDataDetail["error"]; const jobData = jsonDataDetail[0]; const jobNumber = jobData["jobNumber"]; const jobStatus = jobData["jobStatus"]; const customerName = jobData["customerName"]; const shortDescription = jobData["shortDescription"]; const longDescription = jobData["longDescription"]; const activityTypeName = jobData["activityTypeName"]; const serviceUnitName = jobData["serviceUnitName"]; const serviceUnitCode = empJobList[jobID]["serviceUnitCode"]; const location = jobData["location"]; const street = jobData["street"]; const zipCode = jobData["zipCode"]; const city = jobData["city"]; const country = jobData["country"]; const contactPerson = jobData["contactPerson"]; const contactEmail = jobData["contactEmail"]; const contactMobile = jobData["contactMobile"]; const contactPhone = jobData["contactPhone"]; const assignedTo = empJobList[jobID]["assignedTo"]; const startDateTimeLocal = jobData["startDateTimeLocal"]; const dueDateTimeLocal = jobData["dueDateTimeLocal"]; var estimatedHours = jobData["estimatedHours"]; if (estimatedHours) { var hours = Math.floor(estimatedHours) var decimal = estimatedHours - hours; //check if minuttes if (decimal > 0) { var estimatedMin = Math.round(decimal*60) + "<?php echo $locale_text["GPSMAP_min_short"]; ?>"; } else { var estimatedMin = ""; } estimatedHours = hours + "<?php echo $locale_text["GPSMAP_hour_short"]; ?> " + estimatedMin; } else { estimatedHours = "-"; } var customerAddr = (location ? location + ", " : "") + (street ? street + ", " : "") + (zipCode ? zipCode + " " : "") + (city ? city + ", " : "") + (country ? country : ""); var contactInfo = (contactEmail ? "<i class=\"fa-regular fa-envelope\"></i> " +contactEmail + ", " : "") + (contactMobile ? "<i class=\"fa-regular fa-phone\"></i> " + contactMobile + ", " : "") + (contactPhone ? "<i class=\"fa-regular fa-phone-office\"></i> " + contactPhone : ""); var resultHTML = '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_description"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+longDescription+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_act_type"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+activityTypeName+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_customer"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+customerName+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"></div>"; resultHTML += "<div class=\"col-9\">"+customerAddr+"</div>"; resultHTML += "</div>"; if (serviceUnitName) { resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_serviceunit"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">("+serviceUnitCode+") "+serviceUnitName+"</div>"; resultHTML += "</div>"; } resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_contact_person"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+contactPerson+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"></div>"; resultHTML += "<div class=\"col-9\">"+contactInfo+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_startdate"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+startDateTimeLocal+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_deadline"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+dueDateTimeLocal+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_duration"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+estimatedHours+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_employees"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+assignedTo+"</div>"; resultHTML += "</div>"; // Initialize popover with the fetched content $icon.popover({ title: "<div class=\"d-flex justify-content-between fw-bold\"><div>("+jobNumber+") " + shortDescription + "</div><div>"+jobStatusText[jobStatus]+"</div></div>", trigger: "manual", placement: "right", html: true, customClass: "wide-popover600", content: resultHTML }); // Show the popover $icon.popover("show"); } }, beforeSend: function() { }, complete: function() { }, error: function(xhr, status, error) { console.log(error); } }); }, 300); // Delay in milliseconds }); } }, beforeSend: function() { }, complete: function() { }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // Get jobstatus //============================================================================= function getJobstatus(){ var resultHTMLStatusDrop = ""; //resultHTMLStatusDrop += "<option value=\"0\">"+jobStatusText[0]+"</option>"; resultHTMLStatusDrop += "<option value=\"1\" selected=\"selected\">"+jobStatusText[1]+"</option>"; resultHTMLStatusDrop += "<option value=\"2\">"+jobStatusText[2]+"</option>"; resultHTMLStatusDrop += "<option value=\"3\">"+jobStatusText[3]+"</option>"; resultHTMLStatusDrop += "<option value=\"4\">"+jobStatusText[4]+"</option>"; resultHTMLStatusDrop += "<option value=\"5\">"+jobStatusText[5]+"</option>"; resultHTMLStatusDrop += "<option value=\"6\">"+jobStatusText[6]+"</option>"; resultHTMLStatusDrop += "<option value=\"7\">"+jobStatusText[7]+"</option>"; $("#jobStatusListDropDown").html(resultHTMLStatusDrop); $("#jobStatusListDropDown").chosen({width: "100%"}); } //============================================================================= // Get serviceunits //============================================================================= function getServiceUnitList(refID) { var customerId = mapGlobals.JSON_customerListID[refID]; parmData = 'CustomerId='+customerId ; $.ajax({ cache: false, url: "ajax_get_serviceunit_list.php", dataType: "json", data: parmData, success: function(jsonData){ var resultHTMLserviceunits = ""; //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; $.each( jsonData, function( index, item ){ const id = item.id; const relatedTechnicianName = item.relatedTechnicianName; const customerName = item.customerName; const remarks = item.remarks; const active = item.active; const contactName = item.contactName; const contactEmail = item.contactEmail; const contactPhone = item.contactPhone; const contactMobile = item.contactMobile; const name = item.name; const code = item.code; const serialNumber = item.serialNumber; const qrCode = item.qrCode; const country = item.country; const city = item.city; const region = item.region; const street = item.street; const location = item.location; const zipCode = item.zipCode; const attribute = item.attribute; mapGlobals.JSON_serviceUnitID[code] = item; if (active && index != 'error') { resultHTMLserviceunits += "<div class=\"row mt-2\">"; resultHTMLserviceunits += "<div class=\"col listfilterRow d-flex justify-content-between align-items-center\" id=\"sunit_"+code+"\" ><span id=\"sunit_name_"+code+"\" >"+name+"</span> <span> <span id='customerJobcreateIcon' onclick='jobCreateServiceunit(\""+id+"\",\""+name+"\")' title='<?php echo $locale_text["GPSMAP_create_job"]; ?>' ><i class='fa-regular fa-calendar-circle-plus'></i>&nbsp;</span> <span id=\"sunit_name_info_"+code+"\" class='servUnitInfoIcon listIconInfo'><i class='fa-solid fa-circle-info'></i>&nbsp;</span> </span></div>"; resultHTMLserviceunits += "</div>"; } }); $("#customerReferenceListContainer").html(resultHTMLserviceunits); $("#customerReferenceListContainer").removeClass("d-none"); if (resultHTMLserviceunits != "") $("#referenceSearchWrapper").removeClass("d-none"); // Attach hover handler to .listIconInfo within the search results $("#customerReferenceListContainer").on("mouseenter", ".listIconInfo", function () { const $icon = $(this); var divId = $icon.attr('id'); var divIdArr = divId.split("_"); var selectedServUnit = mapGlobals.JSON_serviceUnitID[divIdArr[3]]; var attributeTotal = Object.keys(selectedServUnit.attribute).length; // Dispose of any existing popover to prevent duplicates $(".servUnitInfoIcon").each(function() { $(this).popover("dispose"); }); var borderRight = ""; var colsize = "col-6"; var popoverClass = "wide-popover300"; if ( attributeTotal > 0 ) { borderRight = "border-end"; colsize = "col-3"; popoverClass = "wide-popover600"; } //we uses the lines in the first column to show standard information, attributes are shown in second column, but number of lines depends on how many have data var resultHTML = '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_number"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + selectedServUnit.code + '</div>'; if(attributeTotal > 0) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[0]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[0]["attributeValueName"] ? selectedServUnit.attribute[0]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_name"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + selectedServUnit.name + '</div>'; if(attributeTotal > 1) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[1]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[1]["attributeValueName"] ? selectedServUnit.attribute[1]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_category"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + selectedServUnit.categoryName + '</div>'; if(attributeTotal > 2) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[2]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[2]["attributeValueName"] ? selectedServUnit.attribute[2]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_QR"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.qrCode ? selectedServUnit.qrCode : "") + '</div>'; if(attributeTotal > 3) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[3]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[3]["attributeValueName"] ? selectedServUnit.attribute[3]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_location"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.location ? selectedServUnit.location : "") + '</div>'; if(attributeTotal > 4) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[4]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[4]["attributeValueName"] ? selectedServUnit.attribute[4]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_address"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.street ? selectedServUnit.street : "") + '</div>'; if(attributeTotal > 5) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[5]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[5]["attributeValueName"] ? selectedServUnit.attribute[5]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_zip_city"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.zipCode ? selectedServUnit.zipCode : "") + " " + (selectedServUnit.city ? selectedServUnit.city : "") + '</div>'; if(attributeTotal > 6) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[6]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[6]["attributeValueName"] ? selectedServUnit.attribute[6]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_country"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.country ? selectedServUnit.country : "") + '</div>'; if(attributeTotal > 7) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[7]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[7]["attributeValueName"] ? selectedServUnit.attribute[7]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_contact_person"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.contactName ? selectedServUnit.contactName : "") + '</div>'; if(attributeTotal > 8) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[8]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[8]["attributeValueName"] ? selectedServUnit.attribute[8]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_phone"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.contactPhone ? selectedServUnit.contactPhone : "") + '</div>'; if(attributeTotal > 9) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[9]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[9]["attributeValueName"] ? selectedServUnit.attribute[9]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_cell_phone"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.contactMobile ? selectedServUnit.contactMobile : "") + '</div>'; if(attributeTotal > 10) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[10]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[10]["attributeValueName"] ? selectedServUnit.attribute[9]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="'+colsize+' fw-bold"><?php echo $locale_text["GPSMAP_email"]; ?></div>'; resultHTML += '<div class="'+colsize+' '+borderRight+'">' + (selectedServUnit.contactEmail ? selectedServUnit.contactEmail : "") + '</div>'; if(attributeTotal > 11) { resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[11]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[11]["attributeValueName"] ? selectedServUnit.attribute[9]["attributeValueName"] : "") + '</div>'; } else { resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; } resultHTML += "</div>"; if(attributeTotal > 12) { for(var i = 12; i < attributeTotal; i++) { resultHTML += '<div class="row">'; resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3 '+borderRight+'"></div>'; resultHTML += '<div class="col-3 fw-bold">'+selectedServUnit.attribute[i]["name"]+'</div>'; resultHTML += '<div class="col-3">' + (selectedServUnit.attribute[i]["attributeValueName"] ? selectedServUnit.attribute[i]["attributeValueName"] : "") + '</div>'; resultHTML += "</div>"; } } // Initialize popover with the fetched content $icon.popover({ title: "<?php echo $locale_text["GPSMAP_info"] ?>", trigger: "manual", placement: "right", html: true, customClass: popoverClass, content: resultHTML }); // Attach the event listener for 'inserted.bs.popover' before showing the popover $icon.on('inserted.bs.popover', function () { // Bind click event to each .custResultLine element within the popover $('.popover-body .custResultLine').on('click', function () { fillInMachineInfo(this.id); }); }); // Show the popover $icon.popover("show"); }); } }, beforeSend: function() { }, complete: function() { }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // filter on customerReferenceList //============================================================================= function referenceFilter() { var input = document.getElementById("refFilter"); var filter = input.value.toUpperCase(); var elementsArrayRow = document.getElementsByClassName("listfilterRow"); var filterHit = false; for(var i=0; i<elementsArrayRow.length; i++) { var id = elementsArrayRow[i].id; var txtId = id.replace("sunit", "sunit_name"); var txtValue = document.getElementById(txtId).innerHTML.toUpperCase(); //check if any hit if (txtValue.toUpperCase().indexOf(filter) > -1) { filterHit = true; //show listLabel elementsArrayRow[i].classList.remove("d-none") } else { elementsArrayRow[i].classList.add("d-none") } } if (!filterHit) { $("#refFilterResult").show(); } else { $("#refFilterResult").hide(); } } //============================================================================= // Get activityTypes //============================================================================= function getActTypes(){ $.ajaxq('getQueue',{ cache: false, url: "ajax_get_activitytype_list.php", dataType: "json", success: function(jsonData){ var resultHTMLActTypesDrop = ""; //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; $.each( jsonData, function( index, item ){ const id = item.id; const name = item.name; resultHTMLActTypesDrop += "<option value=\""+id+"\">"+ name +"</option>"; }); $("#jobActTypeListDropDown").html(resultHTMLActTypesDrop); $("#jobActTypeListDropDown").chosen({width: "100%"}); $("#jobCreateActTypeListDropDown").html("<option value=\"\"></option>" + resultHTMLActTypesDrop); $("#jobCreateActTypeListDropDown").chosen({width: "100%", allow_single_deselect: true}); } }, beforeSend: function() { }, complete: function() { }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // Get users Jobs //============================================================================= function getJobs(userId, container) { if (container == "#empTodayJobContainer") { var today = new Date(); var tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); var startDate = today.getDate() + '-' + (today.getMonth() + 1) +'-' + today.getFullYear() + ' 00:00:00'; var endDate = tomorrow.getDate() + '-' + (tomorrow.getMonth() + 1) +'-' + tomorrow.getFullYear() + ' 00:00:00'; } else if (container == "#day-JobContainer") { const selectedDate = $('#day-dateInput').val(); var nextDate = new Date(selectedDate); var startDate = nextDate.getDate() + '-' + (nextDate.getMonth() + 1) +'-' + nextDate.getFullYear() + ' 00:00:00'; nextDate.setDate(nextDate.getDate() + 1); var endDate = nextDate.getDate() + '-' + (nextDate.getMonth() + 1) +'-' + nextDate.getFullYear() + ' 00:00:00'; } else { var startDate = ""; var endDate = ""; } parmData = 'userId='+userId + '&startDate=' + startDate + '&endDate=' + endDate + '&type=**USER**' ; $.ajax({ cache: false, url: "ajax_get_joblist.php", data: parmData, dataType: "json", success: function(jsonData){ //console.log(container); //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; const jobList = jsonData["jobList"]; const jobscheduleList = jsonData["jobscheduleList"]; var resultCount = Object.keys(jobList).length; if ( resultCount == 0 ) { var resultHTML = "<?php echo $locale_text["GPSMAP_noData"]; ?>" } else { var resultHTML = "<div id=\"empTodayJobList\" class=\"overflow-y-auto overflow-x-hidden\" style=\"max-height: 150px;\">"; resultHTML += '<div class="row sticky-top border-bottom fw-bold bg-body-secondary opacity-100 bg-white">'; resultHTML += '<div class="col-2 text-break text-wrap"><?php echo $locale_text["GPSMAP_job"]; ?></div>'; resultHTML += '<div class="col-2 text-break text-wrap"><?php echo $locale_text["GPSMAP_customer"]; ?></div>'; resultHTML += '<div class="col-3 text-break text-wrap"><?php echo $locale_text["GPSMAP_address"]; ?></div>'; resultHTML += '<div class="col-3 text-break text-wrap"><?php echo $locale_text["GPSMAP_duration"]; ?></div>'; resultHTML += '<div class="col-2 text-break text-wrap"></div>'; resultHTML += "</div>"; } $.each( jobList, function( index, item ){ empJobList[item["jobNumber"]] = item; const id = item["id"]; const jobNumber = item["jobNumber"]; const externalJobNumber = item["externalJobNumber"]; const jobTagName = item["jobTagName"]; const activityTypeName = item["activityTypeName"]; const customerName = item["customerName"]; const responsibleName = item["responsibleName"]; const createdByName = item["createdByName"]; const isGroup = item["isGroup"]; const departmentName = item["departmentName"]; const customerCode = item["customerCode"]; const customerCategory = item["customerCategory"]; const serviceUnitCode = item["serviceUnitCode"]; const serviceUnitName = item["serviceUnitName"]; const serviceUnitSerialNumber = item["serviceUnitSerialNumber"]; const serviceUnitCategory = item["serviceUnitCategory"]; const assignedTo = item["assignedTo"]; const completedDateTime = item["completedDateTime"]; const totalScheduledWork = item["totalScheduledWork"]; const totalTimeLogged = item["totalTimeLogged"]; const clientDateTime = item["clientDateTime"]; const isRecurring = item["isRecurring"]; const isCritical = item["isCritical"]; const jobStatus = item["jobStatus"]; const contactPerson = item["contactPerson"]; const contactPhone = item["contactPhone"]; const contactEmail = item["contactEmail"]; const contactMobile = item["contactMobile"]; const shortDescription = item["shortDescription"]; const requisitionNumber = item["requisitionNumber"]; const estimatedHours = item["estimatedHours"]; const startDateTime = item["startDateTime"]; const startDateTimeLocal = item["startDateTimeLocal"]; const dueDateTime = item["dueDateTime"]; const dueDateTimeLocal = item["dueDateTimeLocal"]; const location = item["location"]; const street = item["street"]; const zipCode = item["zipCode"]; const city = item["city"]; const country = item["country"]; const createdAt = item["createdAt"]; const createdDateTime = item["createdDateTime"]; var jobStatusTxt = jobStatusText[jobStatus]; var address = item["location"] + " " + item["street"] + " " + item["zipCode"] + " " + item["city"]+ " " + item["country"] ; address = address.replace("null", "").trim(); var jobschedules = jobscheduleList[jobNumber]; var scheduleHTML = ""; $.each( jobschedules, function( index2, schedule ){ const startDateTimeLocalSchedule = schedule["startDateTimeLocal"]; const durationSchedule = schedule["duration"];; var durationFormatted = getFormattedMinutes(durationSchedule*60); var newline = "<br>"; if (scheduleHTML == "") newline = ""; scheduleHTML += newline + "" + startDateTimeLocalSchedule + " (" + durationFormatted + ")" ; }); resultHTML += '<div class="row border-bottom">'; resultHTML += '<div class="col-2 text-break text-wrap">('+jobNumber+') '+shortDescription+'</div>'; resultHTML += '<div class="col-2 text-break text-wrap">'+customerName+'</div>'; resultHTML += '<div class="col-3 text-break text-wrap">'+address+'</div>'; resultHTML += '<div class="col-3 text-break text-wrap">'+scheduleHTML+'</div>'; resultHTML += '<div id="jobIcons_'+jobNumber+'" class="col-2 text-break text-wrap"><span class=\"jobSearchIcon listIconInfo me-2\"><i class=\"fa-solid fa-circle-info\"></i></span>'; if (container == "#day-JobContainer") { resultHTML += '&nbsp&nbsp<input type="checkbox" class="historyMenuPrint printJob" id="printJob_'+id+'" name="printJob_'+id+'" value="yes" title="<?php echo $locale_text["GPSMAP_print"]; ?>">'; } resultHTML += "</div>"; resultHTML += "</div>"; }); $(container).html(resultHTML); // Add click event to listIconInfo $(container).on("mouseenter", ".listIconInfo", function () { const $icon = $(this); // Dispose of any existing popover to prevent duplicates $(".jobSearchIcon").each(function() { $(this).popover("dispose"); }); var divId = $icon.parent().attr('id'); var divIdArr = divId.split("_"); const id = divIdArr[1]; const jobUuid = empJobList[id]["id"] parmData = 'jobUuid='+jobUuid ; $.ajax({ cache: false, url: "ajax_get_jobdetail.php", data: parmData, dataType: "json", success: function(jsonDataDetail){ //console.log(jsonDataDetail); if (jsonDataDetail["error"] != "") { console.log(jsonDataDetail["error"]); } else { delete jsonDataDetail["error"]; const jobData = jsonDataDetail[0]; const jobNumber = jobData["jobNumber"]; const jobStatus = jobData["jobStatus"]; const customerName = jobData["customerName"]; const shortDescription = jobData["shortDescription"]; const longDescription = jobData["longDescription"]; const activityTypeName = jobData["activityTypeName"]; const serviceUnitName = jobData["serviceUnitName"]; const serviceUnitCode = empJobList[id]["serviceUnitCode"]; const location = jobData["location"]; const street = jobData["street"]; const zipCode = jobData["zipCode"]; const city = jobData["city"]; const country = jobData["country"]; const contactPerson = jobData["contactPerson"]; const contactEmail = jobData["contactEmail"]; const contactMobile = jobData["contactMobile"]; const contactPhone = jobData["contactPhone"]; const assignedTo = empJobList[id]["assignedTo"]; const startDateTimeLocal = jobData["startDateTimeLocal"]; const dueDateTimeLocal = jobData["dueDateTimeLocal"]; var estimatedHours = jobData["estimatedHours"]; if (estimatedHours) { var hours = Math.floor(estimatedHours) var decimal = estimatedHours - hours; //check if minuttes if (decimal > 0) { var estimatedMin = Math.round(decimal*60) + "<?php echo $locale_text["GPSMAP_min_short"]; ?>"; } else { var estimatedMin = ""; } estimatedHours = hours + "<?php echo $locale_text["GPSMAP_hour_short"]; ?> " + estimatedMin; } else { estimatedHours = "-"; } var customerAddr = (location ? location + ", " : "") + (street ? street + ", " : "") + (zipCode ? zipCode + " " : "") + (city ? city + ", " : "") + (country ? country : ""); var contactInfo = (contactEmail ? "<i class=\"fa-regular fa-envelope\"></i> " +contactEmail + ", " : "") + (contactMobile ? "<i class=\"fa-regular fa-phone\"></i> " + contactMobile + ", " : "") + (contactPhone ? "<i class=\"fa-regular fa-phone-office\"></i> " + contactPhone : ""); var resultHTML = '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_description"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+longDescription+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_act_type"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+activityTypeName+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_customer"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+customerName+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"></div>"; resultHTML += "<div class=\"col-9\">"+customerAddr+"</div>"; resultHTML += "</div>"; if (serviceUnitName) { resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_serviceunit"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">("+serviceUnitCode+") "+serviceUnitName+"</div>"; resultHTML += "</div>"; } resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_contact_person"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+contactPerson+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"></div>"; resultHTML += "<div class=\"col-9\">"+contactInfo+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_startdate"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+startDateTimeLocal+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_deadline"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+dueDateTimeLocal+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_duration"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+estimatedHours+"</div>"; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += "<div class=\"col-3 fw-bold\"><?php echo $locale_text["GPSMAP_employees"]; ?>:</div>"; resultHTML += "<div class=\"col-9\">"+assignedTo+"</div>"; resultHTML += "</div>"; // Initialize popover with the fetched content $icon.popover({ title: "<div class=\"d-flex justify-content-between fw-bold\"><div>("+jobNumber+") " + shortDescription + "</div><div>"+jobStatusText[jobStatus]+"</div></div>", trigger: "manual", placement: "right", html: true, customClass: "wide-popover600", content: resultHTML }); // Attach the event listener for 'inserted.bs.popover' before showing the popover $icon.on('inserted.bs.popover', function () { // Bind click event to each .custResultLine element within the popover $('.popover-body .custResultLine').on('click', function () { fillInMachineInfo(this.id); }); }); // Show the popover $icon.popover("show"); } }, beforeSend: function() { }, complete: function() { }, error: function(xhr, status, error) { console.log(error); } }); }); } }, beforeSend: function() { }, complete: function() { }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // Get timelogs //============================================================================= function getTimelogs(userId){ const selectedDate = $('#day-dateInput').val(); var nextDate = new Date(selectedDate); var startDate = nextDate.getDate() + '-' + (nextDate.getMonth() + 1) +'-' + nextDate.getFullYear() + ' 00:00:00'; nextDate.setDate(nextDate.getDate() + 1); var endDate = nextDate.getDate() + '-' + (nextDate.getMonth() + 1) +'-' + nextDate.getFullYear() + ' 23:59:59'; parmData = 'userId='+userId + '&startDate=' + startDate + '&endDate=' + endDate ; $.ajax({ cache: false, url: "ajax_get_timelog.php", data: parmData, dataType: "json", success: function(jsonData){ //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; var resultCount = Object.keys(jsonData).length; if ( resultCount == 0 ) { var resultHTML = "<?php echo $locale_text["GPSMAP_noData"]; ?>" } else { var resultHTML = "<div id=\"day-timesheetContainer-data\" class=\"overflow-y-auto overflow-x-hidden\" style=\"max-height: 150px;\">"; resultHTML += '<div class="row sticky-top border-bottom fw-bold bg-body-secondary opacity-100 bg-white">'; resultHTML += '<div class="col-2 text-break text-wrap"><?php echo $locale_text["GPSMAP_job"]; ?></div>'; resultHTML += '<div class="col-2 text-break text-wrap"><?php echo $locale_text["GPSMAP_customer"]; ?></div>'; resultHTML += '<div class="col-3 text-break text-wrap"><?php echo $locale_text["GPSMAP_address"]; ?></div>'; resultHTML += '<div class="col-2 text-break text-wrap"><?php echo $locale_text["GPSMAP_salary_type"]; ?></div>'; resultHTML += '<div class="col-2 text-break text-wrap"><?php echo $locale_text["GPSMAP_duration"]; ?></div>'; resultHTML += '<div class="col-1 text-break text-wrap"></div>'; resultHTML += "</div>"; $.each( jsonData, function( index, item ){ const id = item["id"]; const jobNumber = item["jobNumber"]; const jobName = item["jobName"]; const customerName = item["customerName"]; var address = item["location"] + " " + item["street"] + " " + item["zipCode"] + " " + item["city"]+ " " + item["country"] ; address = address.replace("null", "").trim(); const salaryTypeName = item["salaryTypeName"]; const statusName = item["statusName"]; const sorttype = item["sorttype"]; const unit = item["unit"]; const unitValue = item["unitValue"]; var hours = ""; if (!unit) { const EndTimeLocal = item[sorttype+"EndTimeLocal"]; const StartTimeLocal = item[sorttype+"StartTimeLocal"]; const endStamp = Math.round( Date.parse( EndTimeLocal ) / 1000); const startStamp = Math.round( Date.parse( StartTimeLocal ) / 1000); var EndTimeLocalArr = EndTimeLocal.split(" "); var EndHourLocalArr = EndTimeLocalArr[1].split(":"); var StartTimeLocalArr = StartTimeLocal.split(" "); var StartHourLocalArr = StartTimeLocalArr[1].split(":"); hours = "<br>("+StartHourLocalArr[0]+":"+StartHourLocalArr[1]+ " - " + EndHourLocalArr[0]+":"+EndHourLocalArr[1] + ")"; var diff = timeDifference(endStamp, startStamp); var duration = getFormattedMinutes(diff); } else { var duration = unitValue + " " + unit; } resultHTML += '<div class="row border-bottom">'; resultHTML += '<div class="col-2 text-break text-wrap">('+jobNumber+') '+jobName+'</div>'; resultHTML += '<div class="col-2 text-break text-wrap">'+customerName+'</div>'; resultHTML += '<div class="col-3 text-break text-wrap">'+address+'</div>'; resultHTML += '<div class="col-2 text-break text-wrap">'+salaryTypeName+' ('+statusName+')</div>'; resultHTML += '<div class="col-2 text-break text-wrap">'+duration+hours+'</div>'; resultHTML += '<div class="col-1 text-break text-wrap"><input type="checkbox" class="historyMenuPrint printScheme" id="printScheme_'+id+'" name="printScheme_'+id+'" value="yes" title="<?php echo $locale_text["GPSMAP_print"]; ?>"></div>'; resultHTML += "</div>"; }); resultHTML += "</div>"; } $("#day-timesheetContainer").html(resultHTML); } }, beforeSend: function() { }, complete: function() { }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // Get days data //============================================================================= function getDayData(){ getRoute('*DAY*'); var userId = $("#empInfoModal-userId").val(); getJobs(userId, "#day-JobContainer"); getTimelogs(userId); } //============================================================================= // Get Route //============================================================================= function getRoute(type){ var parmData = ""; $("#modal-message").addClass("d-none"); $("#hideRouteBtn").click(); $("#printGPSTransactionsAllCheck").prop('checked', false); // Unchecks it if (type == '*DAY*') { const selectedDate = $('#day-dateInput').val(); const deviceId =$("#empInfoModal-deviceId").val(); if (selectedDate.trim() == "") { $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_DATE_WARNING"] ?>' ); $('#day-dateInput').focus(); return; } parmData = 'from_date=' + selectedDate + '&to_date=' + selectedDate + '&device_id=' + deviceId ; } else if (type == '*PERIOD*') { const fromDate = $('#period-fromdateInput').val(); const toDate = $('#period-todateInput').val(); const deviceId =$("#empInfoModal-deviceId").val(); if (fromDate.trim() == "") { $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_FROMDATE_WARNING"] ?>' ); $('#period-fromdateInput').focus(); return; } if (toDate.trim() == "") { $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_TODATE_WARNING"] ?>' ); $('#period-todateInput').focus(); return; } if (toDate < fromDate) { $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_DATE_GREATER"] ?>' ); $('#period-todateInput').focus(); return; } const date1 = new Date(fromDate); const date2 = new Date(toDate); const diffTime = Math.abs(date2 - date1); const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24)); if (diffDays > 31) { $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_PERIOD"] ?>' ); $('#period-todateInput').focus(); return; } parmData = 'from_date=' + fromDate + '&to_date=' + toDate + '&device_id=' + deviceId ; } excelKeys = {}; $.ajaxq('historyQueue',{ url: 'gps_tracker_get_history.php', type: 'GET', data: parmData, dataType: 'json', success: function(jsonData) { if (jsonData["error"] != "") { console.log(jsonData["error"]); } mapGlobals.JSON_gpsTransactions = jsonData.data; var routeArray = new Array(); // holds route info var totalDistance = 0; var totalDuration = 0; var curDistance = 0; var prevTrans = {}; var curTrans = {}; var lastMoveTrans = {}; var firstPauseTrans = {}; var currentRoute = {}; var moving = 'N'; var shortstop = 'N'; excelData = []; excelKeys = {}; for(i in mapGlobals.JSON_gpsTransactions) { curTrans = mapGlobals.JSON_gpsTransactions[i]; // Calculate route distance totalDistance += curTrans["distance"]; curDistance += curTrans["distance"]; // speed is used to decide if we are on the move or not // a route is from A to B ignoring stops under 5 min if (curTrans["speed"] > 0) { if (moving == 'N') { currentRoute["startTime"] = curTrans["time"]; currentRoute["startTimeStamp"] = curTrans["timestamp"]; //stamp in seconds currentRoute["startLat"] = curTrans["latitude"]; currentRoute["startLon"] = curTrans["longitude"]; currentRoute["driving"] = 'Y'; moving = 'Y'; } shortstop = 'N'; lastMoveTrans = curTrans; } else { if (moving == 'Y') { if (timeDifference(curTrans["timestamp"],lastMoveTrans["timestamp"]) >= 300) { // More than 5 min moving = 'N'; if (shortstop == 'Y') { currentRoute["endTime"] = firstPauseTrans["time"]; currentRoute["endTimeStamp"] = firstPauseTrans["timestamp"]; currentRoute["endLat"] = firstPauseTrans["latitude"]; currentRoute["endLon"] = firstPauseTrans["longitude"]; currentRoute["distance"] = curDistance; currentRoute["duration"] = timeDifference(firstPauseTrans["timestamp"],currentRoute["startTimeStamp"]); } else { currentRoute["endTime"] = curTrans["time"]; currentRoute["endTimeStamp"] = curTrans["timestamp"]; currentRoute["endLat"] = curTrans["latitude"]; currentRoute["endLon"] = curTrans["longitude"]; currentRoute["distance"] = curDistance; currentRoute["duration"] = timeDifference(curTrans["timestamp"],currentRoute["startTimeStamp"]); } currentRoute["driving"] = 'N'; routeArray.push(currentRoute); totalDuration += currentRoute["duration"]; //Reset currentRoute = {}; curDistance = 0; shortstop = 'N'; } else if (shortstop == 'N') { shortstop = 'Y'; firstPauseTrans = curTrans; } } } prevTrans = curTrans; } if (!jQuery.isEmptyObject(currentRoute)) { if (shortstop == 'Y') { currentRoute["endTime"] = firstPauseTrans["time"]; currentRoute["endTimeStamp"] = firstPauseTrans["timestamp"]; currentRoute["endLat"] = firstPauseTrans["latitude"]; currentRoute["endLon"] = firstPauseTrans["longitude"]; currentRoute["distance"] = curDistance; currentRoute["duration"] = timeDifference(firstPauseTrans["timestamp"],currentRoute["startTimeStamp"]); currentRoute["driving"] = 'N'; } else { currentRoute["endTime"] = curTrans["time"]; currentRoute["endTimeStamp"] = curTrans["timestamp"]; currentRoute["endLat"] = curTrans["latitude"]; currentRoute["endLon"] = curTrans["longitude"]; currentRoute["distance"] = curDistance; currentRoute["duration"] = timeDifference(curTrans["timestamp"],currentRoute["startTimeStamp"]); currentRoute["driving"] = 'Y'; } routeArray.push(currentRoute); totalDuration += currentRoute["duration"]; } mapGlobals.routeArray = routeArray; // Set html var html = ""; if(routeArray.length > 0){ // If result $("#getrouteBtnDay").addClass("col-disabled"); $("#getrouteBtnPeriod").addClass("col-disabled"); $("#printCol").addClass("col-disabled"); $("#printExcelCol").addClass("col-disabled"); $("#printPeriodCol").addClass("col-disabled"); var excelHeader = {}; excelHeader["start"] = "<?php echo $locale_text["GPSMAP_start"]; ?>"; excelHeader["startLocation"] = ""; excelHeader["stop"] = "<?php echo $locale_text["GPSMAP_stop"]; ?>"; excelHeader["stopLocation"] = ""; excelHeader["distance"] = "<?php echo $locale_text["GPSMAP_distance"]; ?>"; excelHeader["duration"] = "<?php echo $locale_text["GPSMAP_duration"]; ?>"; excelHeader["durationRaw"] = "<?php echo $locale_text["GPSMAP_duration"]; ?>"; excelData.push(excelHeader); html += "<div class=\"border\">"; if (type == "*PERIOD*") { html += "<div id=\"period-gpsContainer-data\" class=\"overflow-y-auto overflow-x-hidden\" style=\"max-height: 300px;\">"; } else { html += "<div id=\"day-gpsContainer-data\" class=\"overflow-y-auto overflow-x-hidden\" style=\"max-height: 150px;\">"; } //header html += "<div class=\"row bg-body-secondary sticky-top border-bottom fw-bold opacity-100 bg-white\">"; html += "<div class=\"col-4 text-break text-wrap\"><?php echo $locale_text["GPSMAP_start"]; ?></div>"; html += "<div class=\"col-4 text-break text-wrap\"><?php echo $locale_text["GPSMAP_stop"]; ?></div>"; html += "<div class=\"col-2 text-break text-wrap\"><?php echo $locale_text["GPSMAP_distance"]; ?></div>"; html += "<div class=\"col-2 text-break text-wrap\"><?php echo $locale_text["GPSMAP_duration"]; ?></div>"; html += "</div>"; for(i in routeArray){ if (type == "*PERIOD*") { var rowId = "routePeriod_" + i; var routeStartId = "routeStartPeriod_" + i; var routeEndId = "routeEndPeriod_" + i; var printRouteChkBox = ""; } else { var rowId = "route_" + i; var routeStartId = "routeStart_" + i; var routeEndId = "routeEnd_" + i; var printRouteChkBox = "<input type=\"checkbox\" class=\"historyMenuPrint inSummation printRoute\" id=\"printRoute_"+ i +"\" name=\"printRoute_"+ i +"\" onclick='recalculateSummations();' value=\"yes\" title=\"<?php echo $locale_text["GPSMAP_print"]; ?>\">"; } if (routeArray[i]["driving"] == 'Y') { var truckIcon = '<span title="<?php echo $locale_text["GPSMAP_still_driving"]; ?>"><i class="fa-sharp fa-thin fa-truck-fast"></i></span>'; } else { var truckIcon = ''; } // row - stopped if (i != 0) { var stopDuration = timeDifference(routeArray[i-1]["endTimeStamp"],routeArray[i]["startTimeStamp"]); html += "<div class=\"row bg-body-secondary border-bottom\">"; html += "<div class=\"col-4 text-break text-wrap\"><?php echo $locale_text["GPSMAP_stopped"]; ?></div>"; html += "<div class=\"col-4 text-break text-wrap\"></div>"; html += "<div class=\"col-2 text-break text-wrap\"></div>"; if (type == '*DAY*') { html += "<div class=\"col-2 text-break text-wrap\">"; html += "<div class=\"row gx-0\">"; html += "<div class=\"col-7 text-break text-wrap\">"+getFormattedMinutes(stopDuration)+"</div>"; html += "<div class=\"col-5 text-break text-wrap text-end\">"; html += "<span id=\"hideRoute_"+ i +"\" onclick=\"hideRoutePart("+i+")\" class=\"listIcon listIconHideRoute cursorPointer invisible\" title=\"<?php echo $locale_text["GPSMAP_hideRoute"]; ?>\" ><i class=\"fad fa-route fa-fw\"></i></span>"; html += "&nbsp;&nbsp;<input type=\"checkbox\" class=\"historyMenuPrint printRoute\" id=\"printStop_" + i + "\" name=\"printStop_" + i + "\" value=\"yes\" title=\"<?php echo $locale_text["GPSMAP_print"]; ?>\">&nbsp&nbsp;"; html += "</div>"; html += "</div>"; html += "</div>"; } else { html += "<div class=\"col-2 text-break text-wrap\">"+getFormattedMinutes(stopDuration)+"</div>"; } html += "</div>"; var excelRow = {}; excelRow["start"] = "<?php echo $locale_text["GPSMAP_stopped"]; ?>"; excelRow["startLocation"] = ""; excelRow["stop"] = ""; excelRow["stopLocation"] = ""; excelRow["distance"] = ""; excelRow["duration"] = getFormattedMinutes(stopDuration); excelRow["durationRaw"] = stopDuration; excelData.push(excelRow); } const routeStartTimeArr = routeArray[i]["startTime"].split(" "); const routeEndTimeArr = routeArray[i]["endTime"].split(" "); const routeStartTimeFormatted = routeStartTimeArr[0] + "<br> " + routeStartTimeArr[1]; const routeEndTimeFormatted = routeEndTimeArr[0] + "<br> " + routeEndTimeArr[1]; // row - driving html += "<div class=\"row border-bottom\">"; html += "<div class=\"col-4 text-break text-wrap\">"; html += "<div class=\"row gx-0\">"; html += "<div class=\"col-5 text-break text-wrap\">"+routeStartTimeFormatted+"</div>"; html += "<div class=\"col-7 text-break text-wrap\"><div id=\""+ routeStartId +"\" class=\"spinner-border spinner-border-sm word-wrap\" aria-hidden=\"true\"></div></div>"; html += "</div>"; html += "</div>"; html += "<div class=\"col-4 text-break text-wrap\">"; html += "<div class=\"row gx-0\">"; html += "<div class=\"col-5 text-break text-wrap\">"+routeEndTimeFormatted+"</div>"; html += "<div class=\"col-7 text-break text-wrap\"><div id=\""+ routeEndId +"\" class=\"spinner-border spinner-border-sm word-wrap\" aria-hidden=\"true\"></div></div>"; html += "</div>"; html += "</div>"; html += "<div class=\"col-2 text-break text-wrap\">"+routeArray[i]["distance"].toFixed(2)+ " " + truckIcon + "<input id=\"distance_" + i + "\" class=\"d-none\" value=\"" + routeArray[i]["distance"] + "\" /></div>"; if (type == '*DAY*') { html += "<div class=\"col-2 text-break text-wrap\">"; html += "<div class=\"row gx-0\">"; html += "<div class=\"col-7 text-break text-wrap\">"+getFormattedMinutes(routeArray[i]["duration"]) + "<input id=\"duration_" + i + "\" class=\"d-none\" value=\"" + routeArray[i]["duration"] + "\" /></div>"; html += "<div class=\"col-5 text-break text-wrap text-end\">"; html += "<span id=\"showRoute_"+ i +"\" onclick=\"showRoutePart("+i+")\" class=\"listIcon listIconShowRoute cursorPointer\" title=\"<?php echo $locale_text["GPSMAP_showRoute"]; ?>\" ><i class=\"fad fa-route fa-fw\" style=\"color: red;\"></i></span>"; html += "<span id=\"hideRoute_"+ i +"\" onclick=\"hideRoutePart("+i+")\" class=\"listIcon listIconHideRoute cursorPointer d-none\" title=\"<?php echo $locale_text["GPSMAP_hideRoute"]; ?>\" ><i class=\"fad fa-route fa-fw\"></i></span>"; html += "&nbsp;&nbsp;"+printRouteChkBox+"&nbsp&nbsp;"; html += "</div>"; html += "</div>"; html += "</div>"; } else { html += "<div class=\"col-2 text-break text-wrap\">"+getFormattedMinutes(routeArray[i]["duration"]) + "<input id=\"duration_" + i + "\" class=\"d-none\" value=\"" + routeArray[i]["duration"] + "\" /></div>"; } html += "</div>"; var excelRow = {}; excelRow["start"] = routeArray[i]["startTime"]; excelRow["startLocation"] = ""; excelRow["stop"] = routeArray[i]["endTime"]; excelRow["stopLocation"] = ""; excelRow["distance"] = routeArray[i]["distance"].toFixed(2); excelRow["duration"] = getFormattedMinutes(routeArray[i]["duration"]); excelRow["durationRaw"] = routeArray[i]["duration"]; excelData.push(excelRow); excelKeys[i] = excelData.length - 1; // Map id to index } var totalDurationTmp = getFormattedMinutes( (totalDuration / 1000) / 60); var totalDurationLabel = ""; if(getFormattedMinutes( (totalDuration / 1000) / 60).hour > 0){ totalDurationLabel += getFormattedMinutes( (totalDuration / 1000) / 60).hour + " <?php echo $locale_text["GPSMAP_hour_short"]; ?> "; } if(getFormattedMinutes( (totalDuration / 1000) / 60).min > 0){ totalDurationLabel += getFormattedMinutes( (totalDuration / 1000) / 60).min + " <?php echo $locale_text["GPSMAP_min_short"]; ?>"; } //totals html += "<div class=\"row bg-body-secondary fw-bold sticky-bottom\">";; html += "<div class=\"col-4 text-break text-wrap\"><?php echo $locale_text["GPSMAP_total"] . " (" . $locale_text["GPSMAP_driving_time"] . ")"; ?></div>"; html += "<div class=\"col-4 text-break text-wrap\"></div>"; html += "<div id=\"totalDistanceSummation\" class=\"col-2 text-break text-wrap\">"+totalDistance.toFixed(2)+" <?php echo $locale_text["GPSMAP_distance"]; ?></div>"; html += "<div id=\"totalDurationSummation\" class=\"col-2 text-break text-wrap;\">"+getFormattedMinutes(totalDuration)+"</div>"; html += "</div>"; $("#totalDistanceSummation_hidden").val(totalDistance.toFixed(2)+" <?php echo $locale_text["GPSMAP_distance"]; ?>"); $("#totalDurationSummation_hidden").val(getFormattedMinutes(totalDuration)); var excelTotal = {}; excelTotal["start"] = "<?php echo $locale_text["GPSMAP_total"] . " (" . $locale_text["GPSMAP_driving_time"] . ")"; ?>"; excelTotal["startLocation"] = ""; excelTotal["stop"] = ""; excelTotal["stopLocation"] = ""; excelTotal["distance"] = totalDistance.toFixed(2)+" <?php echo $locale_text["GPSMAP_distance"]; ?>"; excelTotal["duration"] = getFormattedMinutes(totalDuration); excelTotal["durationRaw"] = totalDuration; excelData.push(excelTotal); html += "</div>"; // div with max-height html += "</div>"; // div with border } else { html += "<div><?php echo $locale_text["GPSMAP_noData"]; ?></div>"; } if (type == '*DAY*') { $("#day-gpsContainer").html(html); } else { $("#period-gpsContainer").html(html); } let geocodePromises = []; if(routeArray.length > 0){ // Reverse geo code to get address's, dones after HTML is set because of async reverse geo coding. for(i in routeArray){ if (type == '*DAY*') { var startAddressId = 'routeStart_'+i; var endAddressId = 'routeEnd_'+i; } else { var startAddressId = 'routeStartPeriod_'+i; var endAddressId = 'routeEndPeriod_'+i; } const startLat = routeArray[i]["startLat"] const endLat = routeArray[i]["endLat"] const startLon = routeArray[i]["startLon"] const endLon = routeArray[i]["endLon"] geocodePromises.push(geoCodeLatLng(startLat, startLon, startAddressId)); geocodePromises.push(geoCodeLatLng(endLat, endLon, endAddressId)); } } // Wait for all geocoding promises to resolve before print or excel Promise.all(geocodePromises).then(() => { // Enable the column by removing the disabled class $("#printCol").removeClass("col-disabled"); // Enable the column $("#printExcelCol").removeClass("col-disabled"); // Enable the column $("#printPeriodCol").removeClass("col-disabled"); // Enable the column $("#getrouteBtnDay").removeClass("col-disabled"); // Enable button $("#getrouteBtnPeriod").removeClass("col-disabled"); // Enable button }).catch((error) => { console.error("Error with geocoding:", error); }); }, beforeSend: function() { $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["GPSMAP_rev_geo_in_progress"] ?>' ); }, complete: function() { $("#modal-message").addClass("d-none").html( '' ); }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // Get car locations. //============================================================================= function getCarlocations(mode){ var parmData = 'time=' + lastUpdated + '&mode=' + mode ; $.ajaxq('getQueue',{ url: 'gps_tracker_get_devices_latest.php', type: 'GET', data: parmData, dataType: 'json', success: function(jsonData) { //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { lastUpdated = jsonData["time"]; } $.each( jsonData.data, function( index, item ){ //console.log(item); var lat = item.lat; var lng = item.lng; var device_data = item.device_data; var imei = device_data.imei; var course = device_data.course; var online = item.online; var speed = item.speed; var status = 0; // red, offline (no data in 24h) var statusColor = 'bg-danger'; var titleText = offlineLegend; if (online != "offline") { if (speed <= 5) { status = 1; // yellow, paused statusColor = 'bg-warning'; titleText = yellowLegend; } else { status = 2; //green, driving statusColor = 'bg-success'; titleText = onlineLegend; } } var n = 1; if (imeiList.includes(imei)) { mapGlobals.JSON_locationList[imei] = item; carData[imei] = []; var latLng = new google.maps.LatLng(lat, lng); var markerData = new MarkerData("employee", latLng, "", "em_" + imei, imei, status, lat, lng, course); n++; carData[imei]["marker"] = markerData; if ($('#employeeShowOffline').prop('checked') || status != 0) { addMarker(markerData); $("#emp_" + imei).addClass("listItemOn"); } // Changes employee status updateStatusColor(imei, statusColor, titleText); } }); }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // update employee status Color //============================================================================= function updateStatusColor(imei, newClass, titleText) { const empId = "emp_"+imei; const badge = document.querySelector(`#${empId} .badge`); if (badge) { // Remove existing background color classes badge.classList.remove('bg-danger', 'bg-success', 'bg-warning'); // Add the new background color class badge.classList.add(newClass); // Set the title attribute if (titleText) { badge.setAttribute('title', titleText); } } if (newClass == "bg-danger") { $("#"+empId).addClass("isOffline"); if ($('#employeeShowOffline').prop('checked')) $("#"+empId).removeClass("d-none"); else $("#"+empId).addClass("d-none"); } else { $("#"+empId).removeClass("isOffline"); $("#"+empId).removeClass("d-none"); } } //============================================================================= // add Marker to the map //============================================================================= function addMarker(markerData){ if(!markerData){ return false; } let marker = mapGlobals.allMarkers[markerData.id]; // Get the marker by ID // General marker settings if (marker) { // Update existing marker //console.log("update") marker.setPosition(markerData.latLng); marker.address = markerData.address; // Custom property marker.taskStatus = markerData.taskStatus; // Custom property marker.taskColor = markerData.taskColor; // Custom property } else { // Create a new marker //console.log("new") marker = new google.maps.Marker({ id: markerData.id, position: markerData.latLng, map: mapGlobals.map, address: markerData.address, draggable: false, taskStatus: markerData.taskStatus || "", taskColor: markerData.taskColor || "" }); // Add the new marker to the global array mapGlobals.allMarkers[markerData.id] = marker; } // Specific marker settings switch(markerData.type){ case "customer": marker.html = fillInfoWindow(markerData); mapGlobals.currentCustomerMarker = marker; setMapCenter(markerData.latLng); marker.setIcon("images/marker/marker_customer1.png"); marker.setTitle("<?php echo $locale_text["GPSMAP_customer"]; ?>"); break; case "address": mapGlobals.addressMarker = marker; setMapCenter(markerData.latLng); marker.setIcon("images/marker/marker_address.png"); break; case "employee": var persID = markerData.id.split("_"); var empId = persID[1]; var init = ""; try { var init = mapGlobals.JSON_employeeList[empId].initials; } catch(err) { return; } var empName = mapGlobals.JSON_employeeList[empId].name; var mobilePhoneNumber = mapGlobals.JSON_employeeList[empId].mobilePhone; var course = markerData.course; var bearing = getDirection(course); marker.setIcon("include/marker_generator.php?text=" + init + "&type=" + markerData.online + "&bearing=" + bearing); checkID = "em_" + persID[1]; for (var i = 0; i < mapGlobals.markerCluster.markers_.length; i++) { if (checkID == mapGlobals.markerCluster.markers_[i].id){ mapGlobals.markerCluster.removeMarker(mapGlobals.markerCluster.markers_[i]); } } mapGlobals.gpsEmployeeMarkersArray.push(marker); mapGlobals.markerCluster.addMarker(marker); break; case "location": marker.setIcon("images/marker/localmarker.png"); mapGlobals.gpsEmpLocationMarkers[markerData.id] = marker; break; case "home": marker.html = fillInfoWindow(markerData); mapGlobals.homeMarker = marker; marker.setIcon("images/marker/marker_home.png"); marker.setTitle("<?php echo $locale_text["GPSMAP_legendHome"]; ?>"); setMapCenter(markerData.latLng); // added to get map showing break; case "department": marker.html = fillInfoWindow(markerData); marker.setIcon("images/marker/marker_department.png"); marker.setTitle(markerData.description); break; case "machine": marker.html = fillInfoWindow(markerData); marker.setIcon("images/marker/marker_machines.png"); marker.setTitle(markerData.description); setMapCenter(markerData.latLng); mapGlobals.selectedMachines[markerData.id] = marker; break; case "job": switch(markerData.taskStatus){ case 0: // NotAssigned color = "<?php echo $DFT_COLOR_JOB_NOT_ASSIGNED; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; case 1: // Active color = "<?php echo $DFT_COLOR_JOB_ACTIVE; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; case 2: // InProgress color = "<?php echo $DFT_COLOR_JOB_START; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; case 3: // OnHold color = "<?php echo $DFT_COLOR_JOB_ONHOLD; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; case 4: // Review color = "<?php echo $DFT_COLOR_JOB_REVIEW; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; case 5: // Completed color = "<?php echo $DFT_COLOR_JOB_CLOSED; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; case 6: // DFT_COLOR_JOB_INVOICED color = "<?php echo $DFT_COLOR_JOB_PARTLY_DONE; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; case 7: // Cancelled color = "<?php echo $DFT_COLOR_JOB_CANCEL; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; default: color = "<?php echo $DFT_COLOR_JOB_DEFAULT; ?>"; colorCode = color.substring(1); taskIcon = "images/marker/marker_job_"+colorCode+".png"; break; } mapGlobals.selectedJobs[markerData.id] = marker; //marker.setIcon("images/marker/marker_job.png"); marker.setTitle(markerData.description); marker.setIcon(taskIcon); marker.setZIndex(100000); marker.taskStatus = markerData.taskStatus; marker.taskColor = colorCode; marker.taskPlannedperson = markerData.taskPlannedperson; //setMapCenter(markerData.latLng); mapGlobals.markerCluster.addMarker(marker); break; case "jobCustomer": marker.setIcon("images/marker/marker_cust.png"); setMapCenter(markerData.latLng); mapGlobals.jobInfoCustMarker = marker; break; case "jobDelivery": marker.setIcon("images/marker/marker_del.png"); setMapCenter(markerData.latLng); mapGlobals.jobInfoDelMarker = marker; break; } marker.addListener('click', function(m) { var markertype = markerData.id.split("_"); if(markertype[0] == "task") { //getJobEdit(markertype[1], m); if(mapGlobals.userLevel != 1) { // Planner / admins can change all jobs javascript:PopWin("../../details.php?taskid="+markertype[1]+"&personid=&referencecode=&status=0",720,1000, m); } else { // Regular user may only change own job. if(mapGlobals.loggedInUser == markerData.taskPlannedperson || mapGlobals.loggedInUser == 0) { javascript:PopWin("../../details.php?taskid="+markertype[1]+"&personid=&referencecode=&status=0",720,1000, m); } else { $javascript:alert('<?php echo $locale_text["ERROR_EDIT_NOT_ALLOWED"]?>'); } } } }); marker.addListener('mouseover', function(m) { var markertype = markerData.id.split("_"); var container = $(document.getElementById("mapContainer")); if (!container.find('#tooltip').length) container.append(jobtooltip); if(markertype[0] == "task") { projection = overlay.getProjection(); var pixel = projection.fromLatLngToContainerPixel(marker.getPosition()); toolTipTimer = setTimeout(function() { showJobInfoPopup(markertype[1], pixel.x, pixel.y); }, 400); } }); marker.addListener('mouseout', function(m) { var markertype = markerData.id.split("_"); if(markertype[0] == "task") { clearTimeout(toolTipTimer); hideJobInfoPopup(); } }); // Job marker have no info window so far. if(markerData.type != "job"){ /* Closing infowindow on the cross, apparently google maps v3 has a bug and the event is fired twice. * No problem here, but if a more complex function is called later on considere it and take measures. */ google.maps.event.addListener(mapGlobals.infoWin, "closeclick", function(){ if(mapGlobals.empInfoWinShown){ mapGlobals.empInfoWinShown = false; } }); google.maps.event.addListener(marker, "click", function () { // Register click event on marker and set info window content if(markerData.type == "address"){ geoCodeCooridinates(this); } else if(markerData.type == "employee"){ mapGlobals.selectedEmployee = persID[1]; setMapCenter(markerData.latLng); $("#gpsSummationHeader, #gpsSummationContainer").addClass("hidden"); var empObj = { empId : mapGlobals.selectedEmployee, empName : empName, mobilePhoneNumber : mobilePhoneNumber } //console.log("emp id " + mapGlobals.selectedEmployee); //showEmpInfo(empObj); $("#empInfo_"+mapGlobals.selectedEmployee).click(); } else{ mapGlobals.infoWin.setContent(this.html); mapGlobals.infoWin.open(mapGlobals.map, this); if(markerData.type == "employee"){ mapGlobals.empInfoWinShown = true; mapGlobals.empInfoWinID = markerData.id; var empID = markerData.id.split("_"); mapGlobals.selectedEmployee = empID[1]; } else{ mapGlobals.empInfoWinShown = false; } } }); } } //============================================================================= // Remove a specific marker //============================================================================= function removeMarker(marker){ if(marker != null){ const markerId = marker.id; marker.setMap(null); // Update the allMarkers array by removing the marker delete mapGlobals.allMarkers[markerId]; } } //============================================================================= //Remove an employee marker //============================================================================= function removeEmployeeMarker(personID){ for(i in mapGlobals.gpsEmployeeMarkersArray){ if(mapGlobals.gpsEmployeeMarkersArray[i].id == "em_" + personID){ removeMarker(mapGlobals.gpsEmployeeMarkersArray[i]); mapGlobals.markerCluster.removeMarker(mapGlobals.gpsEmployeeMarkersArray[i]); } } } //============================================================================= // Get address from coordinates //============================================================================= function geoCodeCooridinates(marker){ var address = ""; if (marker.address != "") { address = marker.address; mapGlobals.infoWin.setContent("<div class='infoBoxWin boldText'>" + address + "</div>"); mapGlobals.infoWin.open(mapGlobals.map, marker); } else { var geocoder = new google.maps.Geocoder(); geocoder.geocode({'latLng': marker.position}, function(results, status) { if(status == google.maps.GeocoderStatus.OK){ if(results[0]){ address = results[0].formatted_address; mapGlobals.infoWin.setContent("<div class='infoBoxWin boldText'>" + address + "</div>"); mapGlobals.infoWin.open(mapGlobals.map, marker); } } else{ //alert("Adress retrieval failed due to: " + status); } // Remove marker when close on infowin is clicked google.maps.event.addListener(mapGlobals.infoWin,'closeclick',function(){ marker.setMap(null); }); }); } } //============================================================================= // Update Job with coordinates //============================================================================= function updateCoordinates(thisJobUuid, longitude, latitude){ var parmData = 'lat=' + latitude + '&lng=' + longitude + '&uuid=' + thisJobUuid ; $.ajax({ url: 'ajax_update_job.php', type: 'GET', data: parmData, dataType: 'json', success: function(jsonData) { //console.log(jsonData); }, error: function(xhr, status, error) { console.log(error); } }); } //============================================================================= // Get address from coordinates //============================================================================= function geoCodeLatLng(lat, lng, addressId){ // use promise to keep track on when geocoding are done return new Promise((resolve, reject) => { var parmData = 'lat=' + lat + '&lng=' + lng ; $.ajaxq('getQueue',{ url: 'gps_tracker_address_reverse.php', type: 'GET', data: parmData, dataType: 'json', success: function(jsonData) { if (jsonData["error"] != "") { console.log(jsonData["error"]); const errmsg = '<?php echo $locale_text["GPSMAP_unknown_location"] ?>'; $("#"+addressId).removeClass("spinner-border").removeClass("spinner-border-sm"); $("#"+addressId).html(errmsg); } else { const location = jsonData["data"]["location"]; const houseNo = (location["house"] != null ? location["house"] : "") var addText = (location["road"] != null ? location["road"] + " " + houseNo + ", <br> " : ""); addText += ((location["city"] != null || location["zip"] != null) ? location["zip"] + " " + location["city"] : " "); if (addText == "") addText = '<?php echo $locale_text["GPSMAP_unknown_location"] ?>'; $("#"+addressId).removeClass("spinner-border").removeClass("spinner-border-sm"); $("#"+addressId).html(addText); //update excel var addTextExcel = result = addText.replace("<br>", ""); var idArr = addressId.split("_"); if (idArr[0] == "routeStart" || idArr[0] == "routeStartPeriod") { if (excelKeys[idArr[1]] !== undefined) { excelData[excelKeys[idArr[1]]].startLocation = addTextExcel; } } else if (idArr[0] == "routeEnd" || idArr[0] == "routeEndPeriod") { if (excelKeys[idArr[1]] !== undefined) { excelData[excelKeys[idArr[1]]].stopLocation = addTextExcel; } } } resolve(); // Resolve the promise once the AJAX call is complete }, error: function(xhr, status, error) { console.log(error); reject(error); // Reject the promise if there's an error } }); }); } //============================================================================= // Get coordinates for address //============================================================================= function geoCodeAddress(markerData, showResultList){ if(showResultList == undefined){ showResultList = false; } if ((markerData.latitude != undefined && markerData.longitude != undefined) && (markerData.latitude != "" && markerData.longitude != "") ){ var lat = markerData.latitude; var lng = markerData.longitude; var latlng = new google.maps.LatLng(lat, lng); markerData.latLng = latlng; addMarker(markerData); return latlng; } else { var geocoder = new google.maps.Geocoder(); geocoder.geocode({'address' : markerData.address}, function(results, status){ if (status == google.maps.GeocoderStatus.OK){ if (markerData.type == "job") { const latitude = results[0].geometry.location.lat(); const longitude = results[0].geometry.location.lng(); var jobIdArr = markerData.id.split("_"); const jobId = jobIdArr[1] const thisJob = mapGlobals.JSON_jobList[jobId]; const thisJobUuid = thisJob.id; mapGlobals.JSON_jobList[jobId]["latitude"] = latitude; mapGlobals.JSON_jobList[jobId]["longitude"] = longitude; updateCoordinates(thisJobUuid, longitude, latitude); } if(showResultList){ var addressSearchResult = $("#addressSearchResult"); addressSearchResult.hide(); addressSearchResult.empty(); if(results.length > 1){ // More than 1 result. const $button = $("#addressSearchBtn"); // Dispose of the existing popover to reset its content $button.popover("dispose"); var resultLi = "<ul class='searchResultList list-group' style='cursor: pointer;'>"; for(i in results){ resultLi += "<li class='custResultLink list-group-item' id='"+ results[i].geometry.location.lat() + "_" + results[i].geometry.location.lng() +"'>" + results[i].formatted_address + "</li>"; } resultLi += "</ul>"; $button.popover({ trigger: "manual", placement: "right", html: true, content: resultLi }); // Attach the event listener for 'inserted.bs.popover' before showing the popover $button.on('inserted.bs.popover', function () { // Bind click event to each .custResultLine element within the popover $('.popover-body .custResultLink').off('click').on('click', function () { var thisId = this.id; var idArr = thisId.split("_"); var latlng = new google.maps.LatLng(idArr[0], idArr[1]); var address = $(this).text(); var markerData = new MarkerData("address", latlng, address, "addressMarker", null, null, null); addMarker(markerData); $("#addressSearchBtn").popover("hide"); }); }); $button.popover("show"); } else{ // Only 1 result. var lat = results[0].geometry.location.lat(); var lng = results[0].geometry.location.lng(); var latlng = new google.maps.LatLng(lat, lng); markerData.latLng = latlng; markerData.address = results[0].formatted_address; addMarker(markerData); } } else{ var lat = results[0].geometry.location.lat(); var lng = results[0].geometry.location.lng(); var latlng = new google.maps.LatLng(lat, lng); markerData.latLng = latlng; markerData.address = results[0].formatted_address; addMarker(markerData); return latlng; } } else{ //alert("Geocode was not successful for the following reason: " + status); alert(markerData.address + "\n<?php echo $locale_text["GPSMAP_noAddress"]; ?>"); if(markerData.type == "job"){ $("#" + markerData.id).removeClass("listItemOn"); } return false; } }); } } //============================================================================= // Calculate the time difference between two stamps. //============================================================================= function timeDifference(stamp1, stamp2){ return Math.abs(stamp1-stamp2); } //============================================================================= // Format sec as hours and min //============================================================================= function getFormattedMinutes(totalSeconds){ var hours = Math.floor(totalSeconds / 3600); totalSeconds = totalSeconds % 3600; var minutes = Math.floor(totalSeconds / 60); var seconds = totalSeconds % 60; var formattedTime = (hours > 0 ? hours + " <?php echo $locale_text["GPSMAP_hour_short"]; ?> " : ""); formattedTime += (minutes > 0 ? minutes + " <?php echo $locale_text["GPSMAP_min_short"]; ?> " : ""); if (formattedTime == "") formattedTime = "<1 <?php echo $locale_text["GPSMAP_min_short"]; ?>"; return formattedTime; } //============================================================================= // Show employees path on map. Draw a polyline. Print marker according to interval //============================================================================= function showRoute(){ var lastCoord = new google.maps.LatLng(); var gpsEmpPathPolyline = new Array(); for(i in mapGlobals.JSON_gpsTransactions){ var tempLatLng = new google.maps.LatLng(mapGlobals.JSON_gpsTransactions[i].latitude, mapGlobals.JSON_gpsTransactions[i].longitude); // For polyline if(tempLatLng.lat() != 0 && tempLatLng.lng() != 0){ // 0,0 coords not show on line if(tempLatLng.lat() != lastCoord.lat() && tempLatLng.lng() != lastCoord.lng()){ gpsEmpPathPolyline.push(tempLatLng); } } lastCoord = tempLatLng; } mapGlobals.routePolyline = drawPolyline(gpsEmpPathPolyline); setMapCenter(tempLatLng); mapGlobals.map.setZoom(11); } //============================================================================= // Show a specific route //============================================================================= function showRoutePart(id){ $("#hideRouteBtn").trigger("click"); removePolyline(mapGlobals.routePolyline); var startStamp = mapGlobals.routeArray[id]["startTimeStamp"]; var stopStamp = mapGlobals.routeArray[id]["endTimeStamp"]; var latLngList = new Array(); var routeStarted = false; for(i in mapGlobals.JSON_gpsTransactions){ // Transactions without coordinate is skipped if(!mapGlobals.JSON_gpsTransactions[i].latitude || !mapGlobals.JSON_gpsTransactions[i].longitude){ continue; } if(mapGlobals.JSON_gpsTransactions[i].timestamp == startStamp){ routeStarted = true; } if(routeStarted){ var latLng = new google.maps.LatLng(mapGlobals.JSON_gpsTransactions[i].latitude, mapGlobals.JSON_gpsTransactions[i].longitude); latLngList.push(latLng); } if(mapGlobals.JSON_gpsTransactions[i].timestamp == stopStamp){ routeStarted = false; break; } } mapGlobals.routePolyline = drawPolyline(latLngList); setMapCenter(latLng); mapGlobals.map.setZoom(11); $("#showRoute_"+ id).addClass("d-none"); $("#hideRoute_"+ id).removeClass("d-none"); } //============================================================================= // Hide a specific route //============================================================================= function hideRoutePart(id){ removePolyline(mapGlobals.routePolyline); $("#showRoute_"+ id).removeClass("d-none"); $("#hideRoute_"+ id).addClass("d-none"); } //============================================================================= // Draw a polyline between cordinates //============================================================================= function drawPolyline(latLngList){ var polyline = new google.maps.Polyline({ path: latLngList, strokeColor: "#FF3D64", strokeOpacity: 1.0, strokeWeight: 3 }); polyline.setMap(mapGlobals.map); google.maps.event.addListener(polyline, 'click', function(event) { removeMarker(mapGlobals.clickedPolyLineMarker); var latLng = new google.maps.LatLng(event.latLng.lat(), event.latLng.lng()); mapGlobals.clickedPolyLineMarker = new google.maps.Marker({ id: "clickedPolyline", position: latLng, icon: "", map: mapGlobals.map, draggable: false }); geoCodeCooridinates(mapGlobals.clickedPolyLineMarker) }); return polyline; } //============================================================================= // Removes polyline from map //============================================================================= function removePolyline(polyline){ if(polyline != undefined){ polyline.setMap(null); } } //============================================================================= // Recalculate Summations //============================================================================= function recalculateSummations(){ var totalDistance = 0; var totalDuration = 0; var hasChecked = false; var elementsArray = document.getElementsByClassName("inSummation"); for(var i=0; i<elementsArray.length; i++) { var id = elementsArray[i].id; var idArr = id.split("_"); var checked = elementsArray[i].checked; if (checked) { hasChecked = true; var thisDistance = document.getElementById("distance_"+idArr[1]).value; var thisDuration = document.getElementById("duration_"+idArr[1]).value; totalDistance += parseFloat(thisDistance.replace(',', '.')); totalDuration += parseInt(thisDuration); } else { $("#printGPSTransactionsAllCheck").prop('checked', false); // Unchecks it } } if (hasChecked) { $("#totalDistanceSummation").html(totalDistance.toFixed(1) + " km"); $("#totalDurationSummation").html(getFormattedMinutes(totalDuration)); } else { $("#totalDistanceSummation").html($("#totalDistanceSummation_hidden").val()); $("#totalDurationSummation").html($("#totalDurationSummation_hidden").val()); } } //============================================================================= //Remove all markers from a given list //============================================================================= function removeAllMarkers(markerList){ for(i in markerList){ markerList[i].setMap(null); } } //============================================================================= // Center map on a latlng //============================================================================= function setMapCenter(latlng){ mapGlobals.map.setCenter(latlng); // Instantly to location } //============================================================================= // Search address //============================================================================= function addressSearch(){ var address = $("#addressSearchVal").val(); if(address != ""){ removeMarker(mapGlobals.addressMarker); var markerData = new MarkerData("address", null, address, "addressMarker", null, null, null); geoCodeAddress(markerData, true); } else{ $("#addressSearchResult").hide(); } } //============================================================================= // Search clear //============================================================================= function addressClear(){ $("#addressSearchVal").val(""); removeMarker(mapGlobals.addressMarker); $("#addressSearchResult").hide(); } //============================================================================= // toggle sidebar //============================================================================= function toggleSidebar() { const sidebar = document.getElementById("sidebar"); const toggleBtn = document.getElementById("toggle-btn"); sidebar.classList.toggle("show"); // Update button text based on sidebar visibility if (sidebar.classList.contains("show")) { $('#toggle-btn').html('<?php echo $locale_text["GPSMAP_menu_hide"]; ?>'); } else { $('#toggle-btn').html('<?php echo $locale_text["GPSMAP_menu_show"]; ?>'); } } //============================================================================= // get directions from degrees //============================================================================= function getDirection(degrees) { const directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']; const anglePerDirection = 45; const offsetAngle = 22.5; // Normalize degrees to be within 0-360 const adjustedDegrees = (degrees % 360 + 360) % 360; // Determine which of the 8 segments it falls into const index = Math.floor((adjustedDegrees + offsetAngle) / anglePerDirection) % directions.length; const direction = directions[index]; return direction; } //============================================================================= // Search for customers //============================================================================= function customerSearch() { var createJobWindow = $("#createJobWindow"); if(createJobWindow.is(":visible")){ createJobWindow.addClass("hidden"); resetCreateJobWindow(); } mapGlobals.custSearching = true; var searchString = $("#customerSearchVal").val(); mapGlobals.searchString = searchString; if(searchString == "<?php echo $locale_text["GPSMAP_writesearch"];?>"){ $("#customerSearchVal").val(""); searchString = ""; } // Prevent duplicate requests if (searchString === lastSearchString) { return; } lastSearchString = searchString; getCustomerList(searchString); } //============================================================================= // Get a customer list. If only one customer, info is filled otherwise a list is show with possible customers //============================================================================= function getCustomerListTimer(bypassTimer) { clearTimeout(inputTimer); var searchString = $("#customerSearchVal").val(); if (searchString.length < 3) { return; } else if (searchString.length === 3) { customerSearch(); return; } if (!bypassTimer) { inputTimer = setTimeout(function () {getCustomerListTimer(true);}, 500); return; } customerSearch(); } //============================================================================= // Get a customer list //============================================================================= function getCustomerList(searchString){ // Limit queue to one pending request if (custQueueCount > 0) { $.ajaxq.clear("custSearchQueue"); custQueueCount = Math.max(custQueueCount - 1, 0); // Decrement the queue count safely } custQueueCount++; parmData = 'searchString='+encodeURI(searchString) ; $.ajaxq("custSearchQueue", { cache: false, url: "ajax_get_customer_search.php", dataType: "json", data: parmData, success: function(jsonData){ //console.log("Search request completed for:", searchString); //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); } else { delete jsonData["error"]; mapGlobals.JSON_customerList = jsonData; if (custPopoverVisible) { $(".popover-body").empty(); // Clear previous popover content } else { // Ensure no old data lingers in the popover if it's not visible $("#customerSearchBtn").popover("dispose"); // Completely remove the popover instance } var resultHTML = "<div id='customerSearchResult' class='resultList'></div>"; var liCount = 0; resultHTML += "<ul id='customerSearchResultUL' class='searchResultList list-group'>"; $.each( jsonData, function( index, item ){ if (item.length !== 0) { liCount++; const ID = item.id; const referenceID = item.code; mapGlobals.JSON_customerListID[referenceID] = ID; const name = item.name; const location = ((!item.location || item.location.toUpperCase() == 'NULL') ? "" : item.location); const street = ((!item.street || item.street.toUpperCase() == 'NULL') ? "" : item.street); const zipCode = ((!item.zipCode || item.zipCode.toUpperCase() == 'NULL') ? "" : item.zipCode); const city = ((!item.city || item.city.toUpperCase() == 'NULL') ? "" : item.city); const country = ((!item.country || item.country.toUpperCase() == 'NULL') ? "" : item.country); var display = "("+referenceID+") "+name; const displayHit = display.toUpperCase().includes(searchString.toUpperCase()); const locationHit = location.toUpperCase().includes(searchString.toUpperCase()); const streetHit = street.toUpperCase().includes(searchString.toUpperCase()); const zipCodeHit = zipCode.toUpperCase().includes(searchString.toUpperCase()); const cityHit = city.toUpperCase().includes(searchString.toUpperCase()); const countryHit = country.toUpperCase().includes(searchString.toUpperCase()); resultHTML += "<li id='refID_" + referenceID + "' class='custResultLink cursorPointer list-group-item'>" + (displayHit ? "<b>" : "") + display + (displayHit ? "</b>" : "") + ", " + (locationHit ? "<b>" : "") + (location != "" ? location + ", " : "") + (locationHit ? "</b>" : "") + (streetHit ? "<b>" : "") + (street != "" ? street + ", " : "") + (streetHit ? "</b>" : "") + (zipCodeHit ? "<b>" : "") + zipCode + (zipCodeHit ? "</b>" : "") + " "+ (cityHit ? "<b>" : "") + city + (cityHit ? "</b>" : "") + " "+ (countryHit ? "<b>" : "") + country + (countryHit ? "</b>" : "") + "</li>"; } }); resultHTML += "</ul>"; if (liCount == 0){ // No result resultHTML += "<?php echo $locale_text["GPSMAP_noData"]; ?>"; mapGlobals.custSearching = false; } resultHTML += "</div>"; // Update content directly in the popover if it is already visible if (custPopoverVisible) { $(".popover-body").empty().html(resultHTML); // Re-bind click events to the updated content $('.popover-body .custResultLink').off('click').on('click', function () { var thisId = this.id; var idArr = thisId.split("_"); if (mapGlobals.currentCustomerMarker !== undefined) { removeMarker(mapGlobals.currentCustomerMarker); } for (var i in mapGlobals.selectedMachines) { removeMarker(mapGlobals.selectedMachines[i]); if (i in mapGlobals.selectedMachines) { // If key exists, it might not because of async reverse geo code delete mapGlobals.selectedMachines[i]; } } fillInCustomerInfo(idArr[1]); $("#hideCustomerBtn").removeClass('d-none'); $('#createCustomerJobBtn').prop('disabled', false); $("#refFilterResult").hide(); $("#refFilter").val(""); }); } else { // Initialize the popover if not visible $("#customerSearchBtn").popover({ title: "<?php echo $locale_text['GPSMAP_Machine']; ?>", trigger: "manual", placement: "bottom", html: true, customClass: "wide-popover", content: resultHTML }); $("#customerSearchBtn").popover("show"); custPopoverVisible = true; // Bind click events to the newly created content $('.popover-body .custResultLink').off('click').on('click', function () { var thisId = this.id; var idArr = thisId.split("_"); if (mapGlobals.currentCustomerMarker !== undefined) { removeMarker(mapGlobals.currentCustomerMarker); } for (var i in mapGlobals.selectedMachines) { removeMarker(mapGlobals.selectedMachines[i]); if (i in mapGlobals.selectedMachines) { // If key exists, it might not because of async reverse geo code delete mapGlobals.selectedMachines[i]; } } fillInCustomerInfo(idArr[1]); $("#hideCustomerBtn").removeClass('d-none'); $('#createCustomerJobBtn').prop('disabled', false); $("#refFilterResult").hide(); $("#refFilter").val(""); }); } } }, complete: function () { custQueueCount = Math.max(custQueueCount - 1, 0); // Decrement the queue count safely }, error: function (xhr, status, error) { if (status !== "abort") { console.error("AJAX error:", status, error); } } }); } //============================================================================= // Fill customer infobox for specific customer //============================================================================= function fillInCustomerInfo(refID){ $.each( mapGlobals.JSON_customerList, function( index, item ){ if(item.referenceID == refID){ const location = ((!item.location || item.location.toUpperCase() == 'NULL') ? "" : item.location); const street = ((!item.street || item.street.toUpperCase() == 'NULL') ? "" : item.street); const zipCode = ((!item.zipCode || item.zipCode.toUpperCase() == 'NULL') ? "" : item.zipCode); const city = ((!item.city || item.city.toUpperCase() == 'NULL') ? "" : item.city); const country = ((!item.country || item.country.toUpperCase() == 'NULL') ? "" : item.country); $("#customerSearchResult").hide(); $("#customerSearchResultUL").html(""); $("#customerSearchVal").val(""); $("#jobCreateModal-custId").val(item.id); $("#jobCreateModal-serviceunitId").val(""); mapGlobals.selectedCustomer = item; $("#createJobFromCustomerBtn").removeClass("mapBtnDisabled"); $("#custNumber").html("<span>"+item.code+"</span>" + "<span id='customerInfoIcon' class='listIconInfo'><i class='fa-solid fa-circle-info'></i></span>"); $("#custName").html(item.name); $("#custLocation").html(location); $("#custAddress").html(street); $("#custZipCity").html(zipCode + " " + city); if(item.streetName != ""){ var address = street + " " + zipCode + " " + city + " " + country; var markerData = new MarkerData("customer", null, address, "ref_" + item.referenceID, item.name); geoCodeAddress(markerData); } return false; //breake out } }); // Show the popover $("#customerSearchBtn").popover("hide"); custPopoverVisible = false; // Set the popover state to hidden $.ajaxq.abort("custSearchQueue"); //aborts the current search request // Attach hover handler to .listIconInfo within the search results $("#customerContentWrapper").on("mouseenter", ".listIconInfo", function () { const $icon = $(this); // Dispose of any existing popover to prevent duplicates and clear any previous timeout $icon.popover("dispose"); //notice no extra data (øvrige data) in 2.0 var resultHTML = '<div class="row">'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_number"]; ?></div>'; resultHTML += '<div class="col-3 border-end">' + mapGlobals.selectedCustomer.referenceID + '</div>'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_contact_person"]; ?></div>'; resultHTML += '<div class="col-3">' + (mapGlobals.selectedCustomer.contactName !== null && mapGlobals.selectedCustomer.contactName.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.contactName : "") + '</div>'; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_name"]; ?></div>'; resultHTML += '<div class="col-3 border-end">' + mapGlobals.selectedCustomer.name + '</div>'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_phone"]; ?></div>'; resultHTML += '<div class="col-3">' + (mapGlobals.selectedCustomer.contactPhone !== null && mapGlobals.selectedCustomer.contactPhone.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.contactPhone : "") + '</div>'; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_location"]; ?></div>'; resultHTML += '<div class="col-3 border-end">' + (mapGlobals.selectedCustomer.location !== null && mapGlobals.selectedCustomer.location.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.location : "") + '</div>'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_cell_phone"]; ?></div>'; resultHTML += '<div class="col-3">' + (mapGlobals.selectedCustomer.contactMobile !== null && mapGlobals.selectedCustomer.contactMobile.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.contactMobile : "") + '</div>'; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_address"]; ?></div>'; resultHTML += '<div class="col-3 border-end">' + (mapGlobals.selectedCustomer.street !== null && mapGlobals.selectedCustomer.street.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.street : "") + '</div>'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_fax"]; ?></div>'; resultHTML += '<div class="col-3">' + (mapGlobals.selectedCustomer.contactFax !== null && mapGlobals.selectedCustomer.contactFax.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.contactFax : "") + '</div>'; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_zip_city"]; ?></div>'; resultHTML += '<div class="col-3 border-end">' + (mapGlobals.selectedCustomer.zipCode !== null && mapGlobals.selectedCustomer.zipCode.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.zipCode : "") + " " + (mapGlobals.selectedCustomer.city !== null && mapGlobals.selectedCustomer.city.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.city : "") + '</div>'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_email"]; ?></div>'; resultHTML += '<div class="col-3">' + (mapGlobals.selectedCustomer.contactEmail !== null && mapGlobals.selectedCustomer.contactEmail.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.contactEmail : "") + '</div>'; resultHTML += "</div>"; resultHTML += '<div class="row">'; resultHTML += '<div class="col-3 fw-bold"><?php echo $locale_text["GPSMAP_country"]; ?></div>'; resultHTML += '<div class="col-3 border-end">' + (mapGlobals.selectedCustomer.country !== null && mapGlobals.selectedCustomer.country.toUpperCase() != 'NULL' ? mapGlobals.selectedCustomer.country : "") + '</div>'; resultHTML += '<div class="col-3 fw-bold"></div>'; resultHTML += '<div class="col-3"></div>'; resultHTML += "</div>"; // Initialize popover with the fetched content $icon.popover({ title: "<?php echo $locale_text["GPSMAP_info"] ?>", trigger: "manual", placement: "right", html: true, customClass: "wide-popover", content: resultHTML }); // Attach the event listener for 'inserted.bs.popover' before showing the popover $icon.on('inserted.bs.popover', function () { // Bind click event to each .custResultLine element within the popover $('.popover-body .custResultLine').on('click', function () { fillInMachineInfo(this.id); }); }); // Show the popover $icon.popover("show"); }); // TODO handle machines from TEO var customerReferenceListContainer = $("#customerReferenceListContainer"); customerReferenceListContainer.addClass("d-none"); $("#referenceSearchWrapper").addClass("d-none"); getServiceUnitList(refID); /* var customerReferenceListContainer = $("#customerReferenceListContainer"); customerReferenceListContainer.addClass("hidden"); var refFilter = $("#referenceSearchWrapper"); refFilter.addClass("hidden"); getReferenceList(refID, "ul", customerReferenceListContainer); */ } //============================================================================= // Fill infoWindow //============================================================================= function fillInfoWindow(markerData){ var html = ""; switch(markerData.type){ case "customer" : html = "<div>" + "<div class='infoWindowHeader'>" + markerData.description + "</div>" + "<div class='infoWindowInfoCol'>" + $("#custLocation").text() + "<br />" + $("#custAddress").text() + "<br />" + $("#custZipCity").text() + "</div>" + "</div>"; break; case "home" : html = "<div>" + "<div class='infoWindowHeader'>" + "<?php echo $locale_text["GPSMAP_legendHome"]; ?>" + "</div>" + "<div style='margin-top: 5px;'>" + markerData.address + "</div>" + "</div>" + "</div>"; break; case "department" : var IDarray = markerData.id.split('_'); var theID = "dep_"+ IDarray[1]; var contactInfo = ""; if (mapGlobals.JSON_departmentContact[theID]["contactPerson"]) contactInfo += mapGlobals.JSON_departmentContact[theID]["contactPerson"]; if (mapGlobals.JSON_departmentContact[theID]["contactEmail"]) contactInfo += ", " + mapGlobals.JSON_departmentContact[theID]["contactEmail"]; if (mapGlobals.JSON_departmentContact[theID]["contactPhoneNumber"]) contactInfo += ", " + mapGlobals.JSON_departmentContact[theID]["contactPhoneNumber"]; if (mapGlobals.JSON_departmentContact[theID]["contactMobilePhoneNumber"]) contactInfo += ", " + mapGlobals.JSON_departmentContact[theID]["contactMobilePhoneNumber"]; if (mapGlobals.JSON_departmentContact[theID]["contactFaxNumber"]) contactInfo += ", " + mapGlobals.JSON_departmentContact[theID]["contactFaxNumber"]; html = "<div>" + "<div class='infoWindowHeader'>" + markerData.description + "</div>" + "<div style='margin-top: 5px;'>" + markerData.address + "</div>" + "<div style='margin-top: 5px;'>" + contactInfo + "</div>" + "</div>"; break; case "machine" : html = "<div>" + "<div class='infoWindowHeader'>" + markerData.description + "</div>" + "<div style='margin-top: 5px;'>" + markerData.address + "</div>" + "</div>" + "</div>"; break; } return html; } //============================================================================= // jQuery - Ready //============================================================================= $(document).ready(function() { $("#loginOrganizationName").html(" " + loginOrganizationName); //get initial data from REEFT 2.0 getJobstatus(); getActTypes(); // rotate carets document.querySelectorAll('.btn-toggle').forEach(button => { button.addEventListener('click', function () { const icon = this.querySelector('.toggle-icon'); icon.classList.toggle('rotate'); }); }); // show sidebar at load toggleSidebar(); $("#job-message").addClass("d-none"); $('.sideCollapsible').on('shown.bs.collapse', function () { if ($('#empInfoModal').hasClass('show')) { $('#empInfoModal').modal('hide'); // Close the modal } }) // Customer search result hover effect $("#customerSearchResult, #addressSearchResult").on("mouseenter", "li.custResultLink", function(){ $(this).addClass("custResultLinkHover"); }); // Customer search result hover effect $("#customerSearchResult, #addressSearchResult").on("mouseleave", "li.custResultLink", function(){ $(this).removeClass("custResultLinkHover"); }); // Reset the value on page refresh $('#addressSearchVal').val(''); $('#customerSearchVal').val(''); // Perform customer search $("#customerSearchBtn").click(function(){ var searchString = $("#customerSearchVal").val(); if (searchString.length < 3) { alert("<?php echo $locale_text["ERROR_MIN3"]; ?>"); } else { customerSearch(); } }); // Remove customer $("#hideCustomerBtn").click(function(event){ if(mapGlobals.currentCustomerMarker != undefined){ removeMarker(mapGlobals.currentCustomerMarker); } for(var i in mapGlobals.selectedMachines){ removeMarker(mapGlobals.selectedMachines[i]); if(i in mapGlobals.selectedMachines){ // if key exists, it might not because of async revers geo code delete mapGlobals.selectedMachines[i]; } } mapGlobals.selectedCustomer = ""; $("#custNumber").html(""); $("#custName").html(""); $("#custLocation").html(""); $("#custAddress").html(""); $("#custZipCity").html(""); $("#refFilter").val(""); $("#createJobFromCustomerBtn").addClass("mapBtnDisabled"); if($("#createJobWindow").is(":visible")){ $("#createJobWindow").addClass("hidden"); resetCreateJobWindow(); } $("#customerReferenceListContainer").addClass("d-none"); $("#refFilterResult").hide(); $("#referenceSearchWrapper").hide(); mapGlobals.custSearching = false; $("#hideCustomerBtn").addClass('d-none'); $('#createCustomerJobBtn').prop('disabled', true); }); //create job for selected customer $("#createCustomerJobBtn").click(function(){ if(mapGlobals.selectedCustomer != ""){ jobCreate(mapGlobals.selectedCustomer); } else{ alert("<?php echo $locale_text["ERROR_CHOOSE_CUST"]; ?>"); } }); // Select an employee and shows it on map $("#employeeListContainer").on("click", ".listItem", function(){ //if(!mapGlobals.depListShow){ // If deplist is shown click wont fire on emplist. var personID = $(this).attr("id").split("_"); personID = personID[1]; if(!$(this).hasClass("listItemOn")){ if (typeof carData[personID] !== "undefined" && carData[personID] !== null) { var markerData = carData[personID]["marker"]; addMarker(markerData); if(mapGlobals.callMapCenter){ // Is not called when using show all btn to trigger click on the listitem. setMapCenter(markerData.latLng); } if($.inArray(personID, mapGlobals.selectedEmployees) == -1){ mapGlobals.selectedEmployees.push(personID); } $(this).addClass("listItemOn"); } else { alert("<?php echo $locale_text["GPSMAP_unknown_location"]; ?>"); } } else{ removeEmployeeMarker(personID); var persIndex = $.inArray(personID, mapGlobals.selectedEmployees); if(persIndex != -1){ mapGlobals.selectedEmployees.splice(persIndex, 1); } $(this).removeClass("listItemOn"); } //} }); // Show all gps emps $("#showAllEmpsBtn").click(function(){ mapGlobals.callMapCenter = false; $(this).addClass("d-none"); $("#hideAllEmpsBtn").removeClass("d-none"); $("#employeeListContainer li.listItem:not(.listItemOn):not(.d-none)").each(function(index){ $(this).trigger("click"); }); mapGlobals.callMapCenter = true; }); // Hide all gps emps $("#hideAllEmpsBtn").click(function(){ $(this).addClass("d-none"); $("#showAllEmpsBtn").removeClass("d-none"); var markers = mapGlobals.markerCluster.getMarkers(); var markersEmpArr = []; for (i = 0; i < markers.length; i++) { var markerId = markers[i].id.split("_"); if(markerId[0] == "em") { markersEmpArr.push(markers[i]); } } mapGlobals.markerCluster.removeMarkers(markersEmpArr); $("#employeeListContainer li.listItemOn:not(.d-none)").each(function(){ $(this).trigger("click"); }); }); // Select a job and shows it on map $("#jobListContainer").on("click", ".jobListItem", function(){ const targetClass = event.target.className; var jobID = $(this).attr("id").split("_"); jobID = jobID[1]; const thisJob = mapGlobals.JSON_jobList[jobID]; const thisJobAdress = mapGlobals.JSON_jobList[jobID]["address"]; var address = thisJob.address; var description = thisJob.shortDescription; var taskStatus = thisJob.jobStatus; var taskLatitude = thisJob.latitude; var taskLongitude = thisJob.longitude; var taskPlannedperson = thisJob.assignedTo; var taskUuid = thisJob.id; var customerUuid = thisJob.customerId; var serviceUnitUuid = thisJob.serviceUnitId; var markerID = $(this).attr("id"); var thisLi = $(this); if(address != ""){ $(this).toggleClass("listItemOn"); if($(this).hasClass("listItemOn")){ var markerData = new MarkerData("job", "", address, markerID, description, "", taskLatitude, taskLongitude,"",taskStatus, taskPlannedperson, taskUuid); geoCodeAddress(markerData); } else{ removeMarker(mapGlobals.selectedJobs[markerID]); mapGlobals.markerCluster.removeMarker(mapGlobals.selectedJobs[markerID]); if(markerID in mapGlobals.selectedJobs){ // if key exists, it might not because of async revers geo code delete mapGlobals.selectedJobs[markerID]; } } } else { parmData = 'taskUuid='+taskUuid ; if (typeof customerUuid !== "undefined" && customerUuid !== null && customerUuid != "null") parmData += '&customerUuid='+customerUuid; if (typeof serviceUnitUuid !== "undefined" && serviceUnitUuid !== null && serviceUnitUuid != "null") parmData += '&serviceUnitUuid='+serviceUnitUuid; $.ajax({ cache: false, url: "ajax_get_jobaddress.php", data: parmData, dataType: "json", success: function(jsonDataAddr){ //console.log(jsonDataAddr); if (jsonDataAddr["error"] != "") { console.log(jsonDataAddr["error"]); } else { delete jsonDataAddr["error"]; const jobData = jsonDataAddr[0]; const longitude = jobData["longitude"]; const latitude = jobData["latitude"]; const location = jobData["location"]; const street = jobData["street"]; const zipCode = jobData["zipCode"]; const city = jobData["city"]; const country = jobData["country"]; var address = location + " " + street + " " + zipCode + " " + city + " " + country; address = address.replace("null", "").trim(); if(address != ""){ thisLi.toggleClass("listItemOn"); if (taskLatitude != "") taskLatitude = latitude; if (taskLongitude != "") taskLongitude = longitude; if(thisLi.hasClass("listItemOn")){ var markerData = new MarkerData("job", "", address, markerID, description, "", taskLatitude, taskLongitude,"",taskStatus, taskPlannedperson, taskUuid); geoCodeAddress(markerData); } else{ removeMarker(mapGlobals.selectedJobs[markerID]); mapGlobals.markerCluster.removeMarker(mapGlobals.selectedJobs[markerID]); if(markerID in mapGlobals.selectedJobs){ // if key exists, it might not because of async revers geo code delete mapGlobals.selectedJobs[markerID]; } } } } }, error: function(xhr, status, error) { console.log(error); } }); } }); // Show all jobs $("#showAllJobsBtn").click(function(){ mapGlobals.callMapCenter = false; $(this).addClass("d-none"); $("#hideAllJobsBtn").removeClass("d-none"); $("#jobListContainer li.listItem:not(.listItemOn):not(.d-none)").each(function(index){ $(this).trigger("click"); }); mapGlobals.callMapCenter = true; }); // Hide all jobs $("#hideAllJobsBtn").click(function(){ $(this).addClass("d-none"); $("#showAllJobsBtn").removeClass("d-none"); var markers = mapGlobals.markerCluster.getMarkers(); var markersEmpArr = []; for (i = 0; i < markers.length; i++) { var markerId = markers[i].id.split("_"); if(markerId[0] == "job") { markersEmpArr.push(markers[i]); } } mapGlobals.markerCluster.removeMarkers(markersEmpArr); $("#jobListContainer li.listItemOn:not(.d-none)").each(function(){ $(this).trigger("click"); }); }); // select all for printing. $("#printGPSTransactionsAllCheck").click(function(){ var elementsArray = document.getElementsByClassName("historyMenuPrint"); for(var i=0; i<elementsArray.length; i++) { var checked = elementsArray[i].checked; if (document.getElementById("printGPSTransactionsAllCheck").checked == true) { elementsArray[i].checked = true; } else { elementsArray[i].checked = false; } } recalculateSummations(); }); // Hide popover when clicking outside $(document).on("click", function (e) { const $target = $(e.target); // Close #customerSearchBtn popover if (!$target.closest("#customerSearchBtn").length && !$target.closest(".popover").length) { $("#customerSearchBtn").popover("hide"); custPopoverVisible = false; } // Close #customerInfoIcon popovers if (!$target.closest("#customerInfoIcon").length && !$target.closest(".popover").length) { $("#customerInfoIcon").popover("hide"); } // Close addressSearchBtn popovers if (!$target.closest("#addressSearchBtn").length && !$target.closest(".popover").length) { $("#addressSearchBtn").popover("hide"); } // Close addressSearchBtn popovers if (!$target.closest(".servUnitInfoIcon").length && !$target.closest(".popover").length) { $(".servUnitInfoIcon").popover("hide"); } // Close addressSearchBtn popovers if (!$target.closest(".jobSearchIcon").length && !$target.closest(".popover").length) { $(".jobSearchIcon").popover("hide"); // Cancel any pending popover initialization due to hoverTimeout clearTimeout(hoverTimeout); } }); // Open pop up window and print dialog. $("#printGPSTransactions").click(function(){ var printRoutes = false; var printJobs = false; var printSchemes = false; var printSomething = false; var elementsArray = document.getElementsByClassName("historyMenuPrint"); for(var i=0; i<elementsArray.length; i++) { var id = elementsArray[i].id; var idArr = id.split("_"); var checked = elementsArray[i].checked; if (checked) { printSomething = true; if (idArr[0] == "printRoute") printRoutes = true; else if (idArr[0] == "printJob") printJobs = true; else if (idArr[0] == "printScheme") printSchemes = true; } } if (printSomething) { $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["GPSMAP_print_wait"] ?>' ); var printWin = window.open("", "printTransactions", "scrollbars=1,height=800,width=800"); // Clear the content of the window printWin.document.open(); printWin.document.writeln(""); // Optional, just to ensure it's visibly cleared printWin.document.close(); var style = "<style>" + "body{font-family: sans-serif;} " + "table{border-collapse:collapse;} " + "table.dataTable { width: 100%;} " + "th{border-bottom: 2px solid #CCCCCC; font-size: small; padding: 5px 5px; text-align: left;} " + "th{font-weight: bold;} " + "td{padding: 5px; border-bottom: 1px solid #E6E6E6; text-align: left;} " + ".empHeader{ margin-top: 5px; margin-bottom: 5px; font-weight: bold; }" + ".jobListIconMenu{ float: right;}" + "#empJobList{ list-style: none; padding: 0px;}" + ".jobInfoLine{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;} " + ".jobInfoLineHeader{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: bold;}" + ".historyMenuPrint{display:none}" + "#empDayJobContainer{border-bottom: 1px solid #E6E6E6;}" + ".jobListItem{border-top: 1px solid #E6E6E6;}" + ".jobListAssignmentItem{border-top: 1px dotted #E6E6E6;}" + "</style>"; printWin.document.writeln(style); } if (printRoutes) { printWin.document.writeln('<div id="empDayJobContainerHeader" class="empHeader"><?php echo $locale_text["GPSMAP_route_stoptime"]; ?></div>'); printWin.document.writeln('<table class="dataTable roundAllOver" cellspacing="0">'); printWin.document.writeln('<tbody id="summationDataSection" class="dataTable">'); var routeArray = document.getElementsByClassName("printRoute"); // Add the header to the table printWin.document.writeln("<tr>"); var headerArr = excelData[0]; var rowContent = ""; for (var key in headerArr) { if (headerArr.hasOwnProperty(key) && key !='durationRaw') { var cell = headerArr[key]; rowContent += "<th>"+cell+"</th>"; } } printWin.document.writeln(rowContent); // Create a table cell for each column printWin.document.writeln("</tr>"); for(var i=0; i<routeArray.length; i++) { var checked = routeArray[i].checked; if (checked) { printWin.document.writeln("<tr>"); var rowArr = excelData[i+1]; var rowContent = ""; for (var key in rowArr) { if (rowArr.hasOwnProperty(key) && key !='durationRaw') { var cell = rowArr[key]; rowContent += "<td>"+cell+"</td>"; } } printWin.document.writeln(rowContent); // Create a table cell for each column printWin.document.writeln("</tr>"); } } // Add the footer to the table printWin.document.writeln("<tr>"); var footerArr = excelData[excelData.length - 1]; var rowContent = ""; for (var key in footerArr) { if (footerArr.hasOwnProperty(key) && key !='durationRaw') { var cell = footerArr[key]; rowContent += "<th>"+cell+"</th>"; } } printWin.document.writeln(rowContent); // Create a table cell for each column printWin.document.writeln("</tr>"); printWin.document.writeln('</tbody>'); printWin.document.writeln('</table>'); } if (printJobs) { printWin.document.writeln('<div id="empDayJobContainerHead" class="empHeader"><?php echo $locale_text["GPSMAP_job"]; ?></div>'); printWin.document.writeln('<div id="empDayJobContainer">'); printWin.document.writeln('<ul id="empJobList">'); var jobArray = document.getElementsByClassName("printJob"); for(var i=0; i<jobArray.length; i++) { var checked = jobArray[i].checked; if (checked) { var parentLI = jobArray[i].closest("li"); printWin.document.writeln(parentLI.outerHTML) } } printWin.document.writeln('</ul>'); printWin.document.writeln('</div>'); } if (printSchemes) { // Add the header to the table printWin.document.writeln('<div id="empTimeshemeContainerHead" class="empHeader"><?php echo $locale_text["GPSMAP_timesheet"]; ?></div>'); printWin.document.writeln('<div id="empTimeshemeContainer">'); printWin.document.writeln('<table class="dataTable roundAllOver" cellspacing="0">'); printWin.document.writeln('<tbody id="sumationDataSection" class="dataTable">'); printWin.document.writeln('<table id="empSchemeList" class="dataTable roundAllOver"><thead class="dataTable"><tr>'); printWin.document.writeln('<th><?php echo $locale_text["GPSMAP_job"]; ?></th>'); printWin.document.writeln('<th><?php echo $locale_text["GPSMAP_customer"]; ?></th>'); printWin.document.writeln('<th><?php echo $locale_text["GPSMAP_address"]; ?></th>'); printWin.document.writeln('<th><?php echo $locale_text["GPSMAP_salary_type"]; ?></th>'); printWin.document.writeln('<th><?php echo $locale_text["GPSMAP_duration"]; ?></th>'); printWin.document.writeln('<th></th>'); printWin.document.writeln('</tr></thead>'); printWin.document.writeln('<tbody>'); var schemeArray = document.getElementsByClassName("printScheme"); for (var i = 0; i < schemeArray.length; i++) { var checked = schemeArray[i].checked; if (checked) { printWin.document.writeln("<tr>"); // Find the closest row (div with class "row") var parentRow = schemeArray[i].closest(".row"); if (parentRow) { // Select all divs where the class starts with "col-" var cols = parentRow.querySelectorAll('[class^="col-"]'); // Extract text content from each column var colTexts = []; for (var j = 0; j < cols.length; j++) { var text = cols[j].textContent.trim(); printWin.document.writeln("<td>"+text+"</td>"); } } printWin.document.writeln("</tr>"); } } printWin.document.writeln('</tbody>'); printWin.document.writeln('</table>'); printWin.document.writeln('</div>'); } if (printSomething) { $("#modal-message").addClass("d-none").html( '' ); printWin.print(); printWin.document.close(); // IE wont print unless document is closed. } }); // Open pop up window and print dialog. $("#printPeriodGPSTransactions").click(function(){ $("#modal-message").removeClass("d-none").html( '<?php echo $locale_text["GPSMAP_print_wait"] ?>' ); var printWin = window.open("", "printTransactions", "scrollbars=1,height=800,width=800"); var style = "<style>" + "body{font-family: sans-serif;} " + "table{border-collapse:collapse;} " + "th{border-bottom: 2px solid #CCCCCC; border-top: 2px solid #CCCCCC; font-size: small; padding: 5px 5px; text-align: left;} " + "th{font-weight: bold;} " + "td{padding: 5px; border-bottom: 1px solid #E6E6E6; text-align: left;} " + ".empHeader{ margin-top: 5px; margin-bottom: 5px; font-weight: bold; }" + "</style>"; printWin.document.writeln(style); printWin.document.writeln($("#selectedEmp").html()); printWin.document.writeln('<div id="periodContainerHeader" class="empHeader"><?php echo $locale_text["GPSMAP_route_stoptime"]; ?></div>'); printWin.document.writeln('<table class="dataTable roundAllOver" cellspacing="0">'); printWin.document.writeln('<tbody id="summationDataSection" class="dataTable">'); for(var i=0; i<excelData.length; i++) { printWin.document.writeln("<tr>"); var rowArr = excelData[i]; var rowContent = ""; for (var key in rowArr) { if (rowArr.hasOwnProperty(key) && key !='durationRaw') { var cell = rowArr[key]; rowContent += "<td>"+cell+"</td>"; } } printWin.document.writeln(rowContent); // Create a table cell for each column printWin.document.writeln("</tr>"); } printWin.document.writeln('</tbody>'); printWin.document.writeln('</table>'); $("#modal-message").addClass("d-none").html( '' ); printWin.print(); printWin.document.close(); // IE wont print unless document is closed. }); //Excel buttons (day and period) $(".excelBtn").click(function(){ var filename = "Reeft_GPS"; var ws = XLSX.utils.json_to_sheet(excelData, {skipHeader:true}); var wb = XLSX.utils.book_new(); // calculate column width const jsonKeys = Object.keys(excelData[0]); var objectMaxLength = []; for (var i = 0; i < excelData.length; i++) { var value = excelData[i]; for (var j = 0; j < jsonKeys.length; j++) { if (typeof value[jsonKeys[j]] == "number") { objectMaxLength[j] = 10; } else { const l = (value[jsonKeys[j]] ? value[jsonKeys[j]].length : 0); objectMaxLength[j] = (objectMaxLength[j] >= l ? objectMaxLength[j] : l); } } } const wscols = objectMaxLength.map(w => { return { wch: w} }); //width, wch (char), wpx (pixel) ws["!cols"] = wscols; XLSX.utils.book_append_sheet(wb, ws, filename); XLSX.writeFile(wb,filename+".xlsx"); }); // customer search $(document).keydown(function(event){ if(!mapGlobals.custSearching){ if($("#customerSearchVal").is(":focus")){ if(event.keyCode == 13){ // Enter $("#custSearhBtn").trigger("click"); } } } if(event.keyCode == 27){ // Escape if($("#customerSearchResult").is(":visible")){ mapGlobals.custSearching = false; $("#customerSearchResult") .hide() .html(""); $("#customerSearchResultUL").html(""); } } }); // Selected departments $("#depListDropDown").change(function() { var selectedDep = $('#depListDropDown').val(); const employeeShowOffline = $('#employeeShowOffline').prop('checked'); if (selectedDep.length > 0) { // Iterate through each <li> in the list $("#employeeList li").each(function() { // Get the class list of the current <li> const classList = $(this).attr("class"); var id = $(this).attr("id"); var idArr = id.split("_"); var imei = idArr[1]; var markerData = carData[imei]["marker"]; // Find the part after "dep_" // [\w-] matches word characters (letters, digits, underscores) and hyphens (-). const depMatch = classList.match(/dep_([\w-]+)/); if (depMatch && selectedDep.includes(depMatch[1])) { if (employeeShowOffline || !$(this).hasClass('isOffline') ) { $(this).removeClass('d-none'); addMarker(markerData); $("#emp_" + imei).addClass("listItemOn"); } } else { $(this).addClass('d-none'); removeEmployeeMarker(imei); $("#emp_" + imei).removeClass("listItemOn"); } }); } else { $("#employeeList li").each(function() { // Get the class list of the current <li> const classList = $(this).attr("class"); var id = $(this).attr("id"); var idArr = id.split("_"); var imei = idArr[1]; var markerData = carData[imei]["marker"]; if (employeeShowOffline || !$(this).hasClass('isOffline') ) { $(this).removeClass('d-none'); addMarker(markerData); $("#emp_" + imei).addClass("listItemOn"); } }); } }) // Selected departments joblist $("#jobDepListDropDown").change(function() { var selectedDep = $('#jobDepListDropDown').val(); if (selectedDep.length > 0) { // Iterate through each option in the list for employee $("#jobEmpListDropDown option").each(function() { // Get the class list of the current <li> const classList = $(this).attr("class"); // Find the part after "dep_" // [\w-] matches word characters (letters, digits, underscores) and hyphens (-). const depMatch = classList.match(/dep_([\w-]+)/);; if ((depMatch && selectedDep.includes(depMatch[1])) || $(this).hasClass('allDep')) { $(this).removeClass('d-none'); $(this).prop("disabled", false); // Ensure the option is enabled } else { $(this).addClass('d-none'); $(this).prop("disabled", true); // Disable the option to hide it in Chosen } }); // Refresh Chosen to reflect the changes for employee $("#jobEmpListDropDown").trigger("chosen:updated"); } else { //employee $("#jobEmpListDropDown option").each(function() { $(this).removeClass('d-none'); $(this).prop("disabled", false); // Ensure the option is enabled }); $("#jobEmpListDropDown").trigger("chosen:updated"); } }) // Selected departments jobcreate $("#jobCreateDepListDropDown").change(function() { var selectedDep = $('#jobCreateDepListDropDown').val(); $("#jobCreate-message").addClass("d-none").html( '' ); if (selectedDep.length > 0) { // Iterate through each option in the list for employee $("#jobCreateEmpListDropDown option").each(function() { // Get the class list of the current <li> const classList = $(this).attr("class"); // Find the part after "dep_" // [\w-] matches word characters (letters, digits, underscores) and hyphens (-). const depMatch = classList.match(/dep_([\w-]+)/);; if ((depMatch && selectedDep.includes(depMatch[1])) || $(this).hasClass('allDep')) { $(this).removeClass('d-none'); $(this).prop("disabled", false); // Ensure the option is enabled } else { $(this).addClass('d-none'); $(this).prop("disabled", true); // Disable the option to hide it in Chosen } }); // Refresh Chosen to reflect the changes for employee $("#jobCreateEmpListDropDown").trigger("chosen:updated"); } else { //employee $("#jobCreateEmpListDropDown option").each(function() { $(this).removeClass('d-none'); $(this).prop("disabled", false); // Ensure the option is enabled }); $("#jobCreateEmpListDropDown").trigger("chosen:updated"); } }) //online $('#employeeShowOffline').change(function() { const isChecked = $(this).prop('checked'); if (isChecked) { $('.isOffline').removeClass('d-none'); } else { $('.isOffline').addClass('d-none'); } $('.isOffline').each(function() { var id = this.id; var idArr = id.split("_"); var imei = idArr[1]; var markerData = carData[imei]["marker"]; if (isChecked) { addMarker(markerData); $("#emp_" + imei).addClass("listItemOn"); } else { removeEmployeeMarker(imei); $("#emp_" + imei).removeClass("listItemOn"); } }); }) //hide show routes $("#showRouteBtn").click(function(){ $(".listIconShowRoute").removeClass("d-none"); $(".listIconHideRoute").addClass("d-none"); $(this).addClass("d-none"); $("#hideRouteBtn").removeClass("d-none"); $("#hideRouteIcon").removeClass("d-none"); removePolyline(mapGlobals.routePolyline); showRoute(); }); $("#hideRouteBtn").click(function(){ $(".listIconShowRoute").removeClass("d-none"); $(".listIconHideRoute").addClass("d-none"); $(this).addClass("d-none"); $("#showRouteBtn").removeClass("d-none"); $("#showRouteIcon").removeClass("d-none"); removeAllMarkers(mapGlobals.gpsEmpLocationMarkers); removePolyline(mapGlobals.routePolyline); removeMarker(mapGlobals.clickedPolyLineMarker); }); //hide route when modal closes $("#empInfoModal").on("hidden.bs.modal", function () { $("#hideRouteBtn").click(); }); //toogle emp modal $('#collapseModalToggle').on('click', function () { const collapseBody = $('#collapse-body'); const icon = $(this).find('.toggle-icon'); // Toggle the collapse state collapseBody.collapse('toggle'); // Change icon based on collapse state collapseBody.on('shown.bs.collapse', function () { icon.removeClass('fa-circle-caret-down').addClass('fa-circle-caret-up'); }); collapseBody.on('hidden.bs.collapse', function () { icon.removeClass('fa-circle-caret-up').addClass('fa-circle-caret-down'); }); }); // Set focus on tabs $('#home-tab').on('shown.bs.tab', function () { $("#modal-message").addClass("d-none"); $("#hideRouteBtn").click(); }) $('#day-tab').on('shown.bs.tab', function () { $("#modal-message").addClass("d-none"); $('#day-dateInput').focus(); }) $('#period-tab').on('shown.bs.tab', function () { $("#modal-message").addClass("d-none"); $("#hideRouteBtn").click(); $('#period-fromdateInput').focus(); }) //Handle All day in jobcreate $("#jobCreateDayCheckbox").change(function () { $("#jobCreate-message").addClass("d-none").html( '' ); if ($(this).is(":checked")) { var selectedDep = $('#jobCreateDepListDropDown').val(); if (selectedDep == "") { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_CHOOSE_DEP"] ?>' ); $("#jobCreateDayCheckbox").prop("checked", false); $('#jobCreateDepListDropDown').focus(); } else { const jobDate = $('#jobCreateDateInput').val(); var todayNumber = new Date(jobDate).getDay(); if ( todayNumber == 0 ) todayNumber = 6; else todayNumber = todayNumber - 1; parmData = 'depUuid='+selectedDep ; $.ajax({ cache: false, url: "ajax_get_availability.php", data: parmData, dataType: "json", success: function(jsonDataDetail){ //console.log(jsonDataDetail); if (jsonDataDetail["error"] != "") { console.log(jsonDataDetail["error"]); } else { delete jsonDataDetail["error"]; const availData = jsonDataDetail[todayNumber]; $('#jobCreateFromtimeInput').val(availData['startTimeOnly']); $('#jobCreateTotimeInput').val(availData['endTimeOnly']); } }, error: function(xhr, status, error) { console.log(error); } }); } } else { $("#jobCreate-message").addClass("d-none").html( '' ); } }); //submit new job $("#jobCreateForm").submit(function (e) { e.preventDefault(); // Prevent default form submission $("#jobCreate-message").addClass("d-none"); const selectedCust = $('#jobCreateModal-custId').val(); const selectedServiceUnit = $('#jobCreateModal-serviceunitId').val(); const selectedDep = $('#jobCreateDepListDropDown').val(); const selectedActType = $('#jobCreateActTypeListDropDown').val(); const selectedEmp = $('#jobCreateEmpListDropDown').val(); const jobName = $('#jobCreateNameInput').val(); const jobDescription = $('#jobCreateDescriptionInput').val(); const jobDate = $('#jobCreateDateInput').val(); const fromTime = $('#jobCreateFromtimeInput').val(); const toTime = $('#jobCreateTotimeInput').val(); // Validate Department and Employee if (!selectedCust) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_CHOOSE_CUST"] ?>' ); return; } if (!selectedDep) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_CHOOSE_DEP"] ?>' ); $('#jobCreateDepListDropDown').focus(); return; } if (!selectedActType) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_CHOOSE_ACT"] ?>' ); $('#jobCreateActTypeListDropDown').focus(); return; } if (jobName.trim() == "" ) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_CHOOSE_JOBNAME"] ?>' ); $('#jobName').focus(); return; } if (!jobDate) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_DATE_WARNING"] ?>' ); $('#jobCreateDateInput').focus(); return; } if (!fromTime) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_FROMDATE_WARNING"] ?>' ); $('#jobCreateFromtimeInput').focus(); return; } if (!toTime) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_TODATE_WARNING"] ?>' ); $('#jobCreateTotimeInput').focus(); return; } if (fromTime > toTime) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_DATE_GREATER"] ?>' ); $('#jobCreateFromtimeInput').focus(); return; } // If valid submit parmData = 'accountId='+selectedCust + '&departmentId=' + selectedDep + '&activityTypeId=' + selectedActType + '&selectedEmp=' + selectedEmp + '&selectedServiceUnit=' + selectedServiceUnit + '&shortDescription=' + jobName + '&longDescription=' + jobDescription + '&startDate=' + jobDate + '&fromTime=' + fromTime + '&toTime=' + toTime ; $.ajax({ cache: false, url: "ajax_create_job.php", data: parmData, method: 'POST', dataType: "json", success: function(jsonData){ //console.log(jsonData); if (jsonData["error"] != "") { console.log(jsonData["error"]); $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_JOBCREATE"] ?>' + ' - ' + jsonData["error"] ); } else { delete jsonData["error"]; const jobId = jsonData["jobId"]; if (!jobId) { $("#jobCreate-message").removeClass("d-none").html( '<?php echo $locale_text["ERROR_JOBCREATE"]?>' ); } else { $('#jobCreateModal').modal('hide'); // Close the modal } } }, error: function(xhr, status, error) { console.log(error); } }); }); }); //============================================================================= // Constructors //============================================================================= // Contruct new MarkerData obj. function MarkerData(type, latLng, address, id, description, online, latitude, longitude, course, taskStatus, taskPlannedperson, taskUuid){ this.type = type; this.latLng = latLng; this.latitude = latitude; this.longitude = longitude; this.address = address; this.id = id; this.description = description; this.online = online; this.course = course; this.taskStatus = taskStatus; this.taskPlannedperson = taskPlannedperson; this.taskUuid = taskUuid; } // --> </script> </head> <body> <div class="container-fluid mt-2"> <div class="card"> <div class="card-header"> <div class="row mt-2"> <div class="col-2 h4"> <img src="images/reeft_logo.png" alt="REEFTwebplanner" /> </div> <div class="col-8 h2 text-center"> <span class="font-weight-bold"><i class="fa fa-car">&nbsp;&nbsp;</i><?php echo $locale_text["GPSMAP_gps"] ?> <span id ="loginOrganizationName"></span></span> </div> <div class="col-2 text-end"> <span id="toggle-btn" onclick="toggleSidebar()"><?php echo $locale_text["GPSMAP_menu_show"] ?></span><br> <span id="close-btn" onclick="window.close()"><i class="fa-solid fa-right-from-bracket"></i></span> </div> </div> </div> <div class="card-body" id="mapContainer"> <!-- Sidebar --> <div class="sidebar overflow-auto" id="sidebar"> <ul class="list-unstyled ps-0"> <!-- Customer --> <li class="mb-1"> <button class="btn btn-toggle d-flex justify-content-between align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#customerCollapse" aria-expanded="false"> <span> <i class="fa fa-user fa-fw me-2"></i><?php echo $locale_text["GPSMAP_customer"]; ?> </span> <i class="fa-sharp fa-solid fa-circle-caret-down toggle-icon"></i> </button> <div class="collapse sideCollapsible" id="customerCollapse"> <div class="input-group my-3" id="customerSearchWrapper"> <input type="text" id="customerSearchVal" class="form-control" placeholder="<?php echo $locale_text["GPSMAP_writesearch"]; ?>" aria-label="<?php echo $locale_text["GPSMAP_customer"]; ?>" aria-describedby="customerSearchBtn" onkeyup="getCustomerListTimer(false);"> <span class="input-group-text" id="customerSearchBtn"><i class="fa-sharp fa-thin fa-magnifying-glass"></i></span> </div> <div id="customerContentWrapper"> <div class="row mt-2"> <div class="col-5"> <?php echo $locale_text["GPSMAP_number"]; ?> </div> <div class="col-7 d-flex justify-content-between align-items-center" id="custNumber"> </div> </div> <div class="row mt-2"> <div class="col-5"> <?php echo $locale_text["GPSMAP_name"]; ?> </div> <div class="col-7" id="custName"> </div> </div> <div class="row mt-2"> <div class="col-5"> <?php echo $locale_text["GPSMAP_location"]; ?> </div> <div class="col-7" id="custLocation"> </div> </div> <div class="row mt-2"> <div class="col-5"> <?php echo $locale_text["GPSMAP_address"]; ?> </div> <div class="col-7" id="custAddress"> </div> </div> <div class="row mt-2"> <div class="col-5"> <?php echo $locale_text["GPSMAP_zip_city"]; ?> </div> <div class="col-7" id="custZipCity"> </div> </div> </div> <div class="border-top my-3"></div> <div id="referenceSearchWrapper" class="inputWrapperField inputWrapperFieldSearch d-none" title="<?php echo $locale_text["GPSMAP_filter"]; ?>"> <input type='text' class='customInput searchField' id='refFilter' onkeyup='referenceFilter()' style='width: 100%;' placeholder='<?php echo $locale_text["GPSMAP_filter"]; ?>'> <div class="border-top my-3"></div> </div> <div id="refFilterResult" style="display: none;"><?php echo $locale_text["GPSMAP_noData"]; ?></div> <div id="customerReferenceListContainer" class="contentSection d-none"></div> <button type="button" id="hideCustomerBtn" class="btn btn-sm btn-secondary d-none"><?php echo $locale_text["GPSMAP_clearBtn"]; ?></button> <button type="button" id="createCustomerJobBtn" class="btn btn-sm btn-secondary" disabled><?php echo $locale_text["GPSMAP_create_job"]; ?> <i class="fa-regular fa-calendar-circle-plus"></i></button> </li> <!-- Employees --> <li class="border-top my-3"></li> <li class="mb-1"> <button class="btn btn-toggle d-flex justify-content-between align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#employeesCollapse" aria-expanded="false"> <span> <i class="fa-sharp fa-light fa-truck me-2"></i><?php echo $locale_text["GPSMAP_employees"]; ?> </span> <i class="fa-sharp fa-solid fa-circle-caret-down toggle-icon"></i> </button> <div class="collapse sideCollapsible" id="employeesCollapse"> <div class="form-check form-switch"> <input class="form-check-input" type="checkbox" role="switch" id="employeeShowOffline"> <label class="form-check-label" for="employeeShowOffline"><?php echo $locale_text["GPSMAP_offline_show"]; ?></label> </div> <select id="depListDropDown" name="depListDropDown" data-placeholder="<?php echo $locale_text["GPSMAP_department"]; ?>" multiple></select> <div id="employeeListContainer" class="my-2"> <ul id="employeeList" name="employeeList" class="list-group"></ul> </div> <button id="showAllEmpsBtn" type="button" class="btn btn-sm btn-secondary d-none"><?php echo $locale_text["GPSMAP_showAll"] ?></button> <button id="hideAllEmpsBtn" type="button" class="btn btn-sm btn-secondary"><?php echo $locale_text["GPSMAP_hideAll"] ?></button> </div> </li> <!-- Job --> <li class="border-top my-3"></li> <li class="mb-1"> <button class="btn btn-toggle d-flex justify-content-between align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#jobCollapse" aria-expanded="false"> <span> <i class="fa-solid fa-square-list me-2"></i><?php echo $locale_text["GPSMAP_job_list"]; ?> </span> <i class="fa-sharp fa-solid fa-circle-caret-down toggle-icon"></i> </button> <div class="collapse sideCollapsible" id="jobCollapse"> <div class="mb-1"><select id="jobDepListDropDown" name="jobDepListDropDown" data-placeholder="<?php echo $locale_text["GPSMAP_department"]; ?>" multiple></select></div> <div class="mb-1"><select id="jobEmpListDropDown" name="jobEmpListDropDown" data-placeholder="<?php echo $locale_text["GPSMAP_employees"]; ?>" multiple></select></div> <div class="mb-1"><select id="jobStatusListDropDown" name="jobStatusListDropDown" data-placeholder="<?php echo $locale_text["GPSMAP_status"]; ?>" multiple></select></div> <div class="mb-1"><select id="jobActTypeListDropDown" name="jobActTypeListDropDown" data-placeholder="<?php echo $locale_text["GPSMAP_act_type"]; ?>" multiple></select></div> <div class="mb-1"> <label for="job-fromdateInput" class="col-form-label"><?php echo $locale_text["GPSMAP_period"]; ?></label> <div class="input-group"> <span class="input-group-text"><?php echo $locale_text["GPSMAP_from"] ?></span> <input type="date" value="<?php echo date('Y-m-d'); ?>" class="form-control" id="job-fromdateInput"> </div> </div> <div class="mb-1"> <div class="input-group"> <span class="input-group-text"><?php echo $locale_text["GPSMAP_to"] ?></span> <input type="date" value="<?php echo date('Y-m-d', strtotime("+ 1 month")); ?>" class="form-control" id="job-todateInput"> </div> </div> <div class="row mb-1"> <div class="col-6"> <button id="getJobBtn" type="button" class="btn btn-sm btn-secondary" onclick="getJoblist()"><?php echo $locale_text["GPSMAP_load_job_list"] ?></button> </div> <div class="col-6"> <div class="col-6 form-check form-switch"> <input class="form-check-input" type="checkbox" role="switch" id="jobGetUnassigned"> <label class="form-check-label" for="jobGetUnassigned"><?php echo $locale_text["GPSMAP_include_pool_job"]; ?></label> </div> </div> </div> <div class="d-none my-2 p-2 font-weight-bold border border-danger border-4 rounded" id="job-message">&nbsp;</div> <div id="jobListContainer" class="mb-2"> <div id="jobListSpinner" class="d-none"> <div class="spinner-border spinner-border-sm"aria-hidden="true"></div> <span role="status"><?php echo $locale_text["GPSMAP_loading"]; ?></span> </div> <ul id="mainJobList" name="mainJobList" class="list-group"></ul> </div> <button id="showAllJobsBtn" type="button" class="btn btn-sm btn-secondary d-none"><?php echo $locale_text["GPSMAP_showAll"] ?></button> <button id="hideAllJobsBtn" type="button" class="btn btn-sm btn-secondary d-none"><?php echo $locale_text["GPSMAP_hideAll"] ?></button> <button id="clearAllJobsBtn" type="button" onclick="clearJoblist()" class="btn btn-sm btn-secondary d-none"><?php echo $locale_text["GPSMAP_clearBtn"] ?></button> </div> <li class="border-top my-3"></li> <!-- Search --> <li class="mb-1"> <button class="btn btn-toggle d-flex justify-content-between align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#addressSearchCollapse" aria-expanded="false"> <span> <i class="fa-solid fa-building-magnifying-glass me-2"></i></i><?php echo $locale_text["GPSMAP_addresssearch"]; ?> </span> <i class="fa-sharp fa-solid fa-circle-caret-down toggle-icon"></i> </button> <div class="collapse sideCollapsible" id="addressSearchCollapse"> <div class="input-group my-3" id="addressSearchWrapper"> <span class="input-group-text" id="addressClearBtn" onclick="addressClear()" title="<?php echo $locale_text["GPSMAP_clearBtn"]; ?>"><i class="fa-light fa-square-xmark"></i></span> <input type="text" id="addressSearchVal" class="form-control" placeholder="<?php echo $locale_text["GPSMAP_search"]; ?>" aria-label="<?php echo $locale_text["GPSMAP_addresssearch"]; ?>" aria-describedby="addressSearchBtn"> <span class="input-group-text" id="addressSearchBtn" onclick="addressSearch()"><i class="fa-sharp fa-thin fa-magnifying-glass"></i></span> </div> <div id="addressSearchResult" class="resultList" style="display: none; width: 300px;"></div> </div> </li> <li class="border-top my-3"></li> </ul> </div> <!-- Map Container --> <div class="map-container" id="map"></div> </div> </div> </div> <!-- Set footer --> <?php include "include/footer.php"; ?> <!-- Set footer --> <!-- ========================================================================== --> <!-- M O D A L S --> <!-- ========================================================================== --> <!-- Modal start - employee info --> <div class="modal fade" id="empInfoModal" tabindex="-1" data-bs-backdrop="static" aria-labelledby="empInfoModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content opacity-85"> <div class="modal-header d-flex justify-content-between align-items-center"> <h5 class="modal-title" id="empInfoModalLabel"><?php echo $locale_text["GPSMAP_info"] ?></h5> <div class="d-flex align-items-center"> <button type="button" class="btn" id="collapseModalToggle" aria-expanded="true" aria-controls="collapse-body"> <i class="fa-sharp fa-solid fa-circle-caret-up toggle-icon"></i> </button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> </div> <div class="collapse show" id="collapse-body"> <div id="empInfoModal-body" class="modal-body overflow-auto" style="max-height: 60vh;"> <input class="d-none" type="text" id="empInfoModal-userId"> <input class="d-none" type="text" id="empInfoModal-deviceId"> <div class="d-none mb-2 p-2 font-weight-bold border border-danger border-4 rounded" id="modal-message">&nbsp;</div> <!-- Tabs Navigation --> <ul class="nav nav-tabs" id="infoTabs" role="tablist"> <li class="nav-item" role="presentation"> <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true"><?php echo $locale_text["GPSMAP_info"] ?></button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="day-tab" data-bs-toggle="tab" data-bs-target="#day" on type="button" role="tab" aria-controls="day" aria-selected="false"><?php echo $locale_text["GPSMAP_day"] ?></button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="period-tab" data-bs-toggle="tab" data-bs-target="#period" type="button" role="tab" aria-controls="period" aria-selected="false"><?php echo $locale_text["GPSMAP_period"] ?></button> </li> </ul> <!-- Tabs Info Content --> <div class="tab-content" id="infoTabContent"> <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab"> <div class="row mt-3"> <label for="empTodayJobContainer" class="col-form-label"><?php echo $locale_text["GPSMAP_scheduled_jobs"]; ?></label> <div id="empTodayJobContainer"> <div class="spinner-border spinner-border-sm"aria-hidden="true"></div> <span role="status"><?php echo $locale_text["GPSMAP_loading"]; ?></span></div> </div> </div> <!-- Tabs Day Content --> <div class="tab-pane fade" id="day" role="tabpanel" aria-labelledby="day-tab"> <div class="row mt-3"> <div class="col-2"> <label for="day-dateInput" class="col-form-label"><?php echo $locale_text["GPSMAP_select_date"]; ?></label> </div> <div class="col-3"> <input type="date" max="<?php echo date('Y-m-d'); ?>" value="<?php echo date('Y-m-d'); ?>" class="form-control" id="day-dateInput"> </div> <div class="col-2"> <button id="getrouteBtnDay" type="button" class="btn btn-secondary" onclick="getDayData()"><?php echo $locale_text["GPSMAP_search"] ?></button> </div> <div id ="printCol" class="col-5 text-end col-disabled"> <span id="printGPSTransactionsAll"><?php echo $locale_text["GPSMAP_print_all"]; ?>&nbsp<input type="checkbox" id="printGPSTransactionsAllCheck" name="printGPSTransactionsAllCheck" value="yes">&nbsp&nbsp</span> <span id="printGPSTransactions" title="<?php echo $locale_text["GPSMAP_print_driving_report"]; ?>"><i class="fa-light fa-print"></i></span> </div> </div> <div class="row mt-3"> <div class="col-4 text-start"> <?php echo $locale_text["GPSMAP_route_stoptime"]; ?> </div> <div class="col-4 text-center"> <span id="showRouteBtn" class="routeBtn"><?php echo $locale_text["GPSMAP_showWholeRoute"]; ?> &nbsp; <span id="showRouteIcon" class='listIcon listIconShowRoute cursorPointer' title='<?php echo $locale_text["GPSMAP_showRoute"]; ?>' ><i class="fad fa-route fa-fw" style="color: red;"></i></span></span> <span id="hideRouteBtn" class="routeBtn d-none"><?php echo $locale_text["GPSMAP_hideWholeRoute"]; ?> &nbsp; <span id="hideRouteIcon" class='listIcon listIconHideRoute cursorPointer' title='<?php echo $locale_text["GPSMAP_hideRoute"]; ?>' ><i class="fad fa-route fa-fw"></i></span> </div> <div id ="printExcelCol" class="col-4 text-end col-disabled"> <span class="excelBtn" title="<?php echo $locale_text["GPSMAP_excel"]; ?>"><i class="fa-light fa-file-excel"></i></span>&nbsp&nbsp </div> </div> <div class="row mt-3"> <div id="day-gpsContainer" class="container"></div> <input id="totalDistanceSummation_hidden" type="hidden"> <input id="totalDurationSummation_hidden" type="hidden"> </div> <div class="row mt-3"> <label for="day-JobContainer" class="col-form-label"><?php echo $locale_text["GPSMAP_job"]; ?></label> <div id="day-JobContainer" class="container"></div> </div> <div class="row mt-3"> <label for="day-timesheetContainer" class="col-form-label"><?php echo $locale_text["GPSMAP_timesheet"]; ?></label> <div id="day-timesheetContainer" class="container"></div> </div> </div> <!-- Tabs Period Content --> <div class="tab-pane fade" id="period" role="tabpanel" aria-labelledby="period-tab"> <div class="row mt-3"> <div class="col-2"> <label for="period-fromdateInput" class="col-form-label"><?php echo $locale_text["GPSMAP_select_period"]; ?></label> </div> <div class="col-3"> <input type="date" max="<?php echo date('Y-m-d'); ?>" value="<?php echo date('Y-m-d', strtotime("-2 days")); ?>" class="form-control" id="period-fromdateInput"> </div> <div class="col-1"> <label for="period-todateInput" class="col-form-label"><?php echo $locale_text["GPSMAP_to"] ?></label> </div> <div class="col-3"> <input type="date" max="<?php echo date('Y-m-d'); ?>" value="<?php echo date('Y-m-d', strtotime("-1 days")); ?>" class="form-control" id="period-todateInput"> </div> <div class="col-2"> <button id="getrouteBtnPeriod" type="button" class="btn btn-secondary" onclick="getRoute('*PERIOD*')"><?php echo $locale_text["GPSMAP_search"] ?></button> </div> </div> <div class="row mt-3"> <div class="col-4 text-start"> <?php echo $locale_text["GPSMAP_route_stoptime"]; ?> </div> <div class="col-4 text-center"> </div> <div id ="printPeriodCol" class="col-4 text-end"> <span class="excelBtn" title="<?php echo $locale_text["GPSMAP_excel"]; ?>"><i class="fa-light fa-file-excel"></i></span>&nbsp&nbsp <span id="printPeriodGPSTransactions" title="<?php echo $locale_text["GPSMAP_print_driving_report"]; ?>"><i class="fa-light fa-print"></i></span> </div> </div> <div class="row mt-3"> <div id="period-gpsContainer" class="container"></div> </div> </div> </div> </div> </div> </div> </div> </div> <!-- Modal end --> <!-- Modal start - jobcreate --> <div class="modal fade" id="jobCreateModal" tabindex="-1" data-bs-backdrop="static" aria-labelledby="jobCreateModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content opacity-85"> <div class="modal-header d-flex justify-content-between align-items-center"> <h5 class="modal-title" id="jobCreateModalLabel"><?php echo $locale_text["GPSMAP_create_job"] ?></h5> <div class="d-flex align-items-center"> <button type="button" class="btn" id="collapseModalToggle" aria-expanded="true" aria-controls="collapse-body"> <i class="fa-sharp fa-solid fa-circle-caret-up toggle-icon"></i> </button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> </div> <div class="collapse show" id="collapse-body"> <div id="jobCreateModal-body" class="modal-body overflow-auto" > <form id="jobCreateForm"> <input class="d-none" type="text" id="jobCreateModal-custId"> <input class="d-none" type="text" id="jobCreateModal-serviceunitId"> <div class="row mb-3 align-items-center"> <div class="col-md-6"> <label for="jobCreateDepListDropDown" class="form-label"><?php echo $locale_text["GPSMAP_department"] ?></label> <select id="jobCreateDepListDropDown" name="jobCreateDepListDropDown" class="form-select"> </select> </div> <div class="col-md-6"> <label for="jobCreateActTypeListDropDown" class="form-label"><?php echo $locale_text["GPSMAP_act_type"] ?></label> <select id="jobCreateActTypeListDropDown" name="jobCreateActTypeListDropDown" class="form-select"> </select> </div> </div> <div class="row mb-3 align-items-center"> <div class="col-md-12"> <label for="jobCreateNameInput" class="form-label"><?php echo $locale_text["GPSMAP_jobname"] ?></label> <input type="text" id="jobCreateNameInput" name="jobCreateNameInput" class="form-control"> </div> </div> <div class="row mb-3 align-items-center"> <div class="col-md-12"> <label for="jobCreateDescriptionInput" class="form-label"><?php echo $locale_text["GPSMAP_description"] ?></label> <textarea id="jobCreateDescriptionInput" name="jobCreateDescriptionInput" class="form-control" rows="3"></textarea> </div> </div> <div class="row mb-3 align-items-center"> <div class="col-md-3"> <label for="jobCreateEmpListDropDown" class="form-label"><?php echo $locale_text["GPSMAP_employee"] ?></label> <select id="jobCreateEmpListDropDown" name="jobCreateEmpListDropDown" class="form-select"> </select> </div> <div class="col-md-3"> <label for="jobCreateDateInput" class="form-label"><?php echo $locale_text["GPSMAP_date"] ?></label> <input type="date" id="jobCreateDateInput" name="jobCreateDateInput" class="form-control" min="<?php echo date('Y-m-d'); ?>" value="<?php echo date('Y-m-d'); ?>"> </div> <div class="col-md-2"> <label for="jobCreateFromtimeInput" class="form-label"><?php echo $locale_text["GPSMAP_starttime"] ?></label> <input type="time" id="jobCreateFromtimeInput" name="jobCreateFromtimeInput" class="form-control"> </div> <div class="col-md-2"> <label for="jobCreateTotimeInput" class="form-label"><?php echo $locale_text["GPSMAP_endtime"] ?></label> <input type="time" id="jobCreateTotimeInput" name="jobCreateTotimeInput" class="form-control"> </div> <div class="col-md-2"> <label for="jobCreateDayCheckbox" class="form-label"><?php echo $locale_text["GPSMAP_allday"] ?></label> <div class="form-check"> <input class="form-check-input" type="checkbox" id="jobCreateDayCheckbox" name="jobCreateDayCheckbox"> </div> </div> </div> <div class="d-none my-2 p-2 font-weight-bold border border-danger border-4 rounded" id="jobCreate-message">&nbsp;</div> <div class="row"> <div class="col"> <button type="submit" class="btn btn-secondary"><?php echo $locale_text["GPSMAP_save"] ?></button> </div> </div> </form> </div> </div> </div> </div> </div> <!-- Modal end --> <!-- Define initMap as a global function, placed here to ensure everything is read in DOM --> <script> window.initMap = function() { var location = { lat: dftMapCenterLat, lng: dftMapCenterLng }; var mapOptions = { zoom: dftZoomlevel, center: location }; mapGlobals.map = new google.maps.Map(document.getElementById('map'), mapOptions); overlay = new google.maps.OverlayView(); overlay.draw = function() {}; overlay.setMap(mapGlobals.map); mapGlobals.infoWin = new google.maps.InfoWindow(); // Popup window for markers var getGoogleClusterInlineSvg = function (color) { var encoded = window.btoa('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-100 -100 200 200"><defs><g id="a" transform="rotate(45)"><path d="M0 47A47 47 0 0 0 47 0L62 0A62 62 0 0 1 0 62Z" fill-opacity="0.7" stroke="#C3C3C3" stroke-width="1"/><path d="M0 67A67 67 0 0 0 67 0L81 0A81 81 0 0 1 0 81Z" fill-opacity="0.5" stroke="#C3C3C3" stroke-width="1"/><path d="M0 86A86 86 0 0 0 86 0L100 0A100 100 0 0 1 0 100Z" fill-opacity="0.3" stroke="#C3C3C3" stroke-width="1"/></g></defs><g fill="' + color + '"><circle r="42" stroke="#C3C3C3" stroke-width="2"/><use xlink:href="#a"/><g transform="rotate(120)"><use xlink:href="#a"/></g><g transform="rotate(240)"><use xlink:href="#a"/></g></g></svg>'); return ('data:image/svg+xml;base64,' + encoded); }; var cluster_styles = [ { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_NOT_ASSIGNED; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_ACTIVE; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_START; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_ONHOLD; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_REVIEW; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_CLOSED; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_INVOICED; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('<?php echo $DFT_COLOR_JOB_CANCEL; ?>'), textSize: 12 }, { width: 70, height: 70, url: getGoogleClusterInlineSvg('#C3C3C3'), textSize: 12 }, ]; var clusterOptions = { zoomOnClick: false, averageCenter: true, styles: cluster_styles, gridSize: 5, debug: true // Enable debugging } mapGlobals.markerCluster = new MarkerClusterer(mapGlobals.map, [], clusterOptions); /** * It's important to remember that this function runs for EACH cluster individually. * @param {Array} markers Set of markers for this cluster. * @param {Number} numStyles Number of styles we have to play with (set in clusterOptions). */ mapGlobals.markerCluster.setCalculator(function(markers, numStyles){ var index = 0; var count = markers.length; var dv = count; while (dv !== 0) { dv = parseInt(dv / 10, 10); index++; } index = Math.min(index, numStyles); //max jobstatus is 7, so 8 indicates only workers var minStatus = 8; markers.forEach(function(marker) { if(marker.taskStatus != ""){ tmpStatus = parseInt(marker.taskStatus); minStatus = Math.min(status,minStatus); } }); return { text: count, index: minStatus }; }); google.maps.event.addListener(mapGlobals.markerCluster, 'clusterclick', function(cluster){ mapGlobals.infoBubble = new InfoBubble({ maxWidth: 300 }); var markers = cluster.getMarkers(); var showEmp = false; var showJob = false; var infoTextEmp = "<ul>"; var infoTextJob = "<ul>"; for (i = 0; i < markers.length; i++) { var markerId = markers[i].id.split("_"); if(markerId[0] == "em") { showEmp = true; var init = ""; try { var init = mapGlobals.JSON_employeeList[markerId[1]].initials; } catch(err) { return; } var empName = mapGlobals.JSON_employeeList[markerId[1]].name; var phone = mapGlobals.JSON_employeeList[markerId[1]].phone; infoTextEmp += "(" + init + ")" + " " + empName + " " + phone + "<br>"; } else { showJob = true; var description = ""; try { var description = mapGlobals.selectedJobs[markers[i].id].title; } catch(err) { return; } var icon = mapGlobals.selectedJobs[markers[i].id].icon; var iconPath = icon.split("."); var color = iconPath[0].split("_"); var taskPlannedperson = mapGlobals.selectedJobs[markers[i].id].taskPlannedperson; var tmpEditLink = ""; if(mapGlobals.userLevel != 1) { // Planner / admins can change all jobs tmpEditLink = "onclick=\"return showJobdetails(" +markerId[1]+ ")\""; } else { // Regular user may only change own job. if(mapGlobals.loggedInUser == taskPlannedperson || mapGlobals.loggedInUser == 0) { tmpEditLink = "onclick=\"return showJobdetails(" +markerId[1]+ ")\""; } else { tmpEditLink = "onclick=\"javascript:alert('<?php echo $locale_text["ERROR_EDIT_NOT_ALLOWED"];?>')\""; } } infoTextJob += "<li style='background-color: #"+color[2]+";'><span "+tmpEditLink+" class='markerInfoIcon cursorPointer' title= '<?php echo $locale_text["GPSMAP_job_info"]; ?>' style='padding-top: 16px;'></span><span style='color: #000000; font-weight: bold;'> " + " " + description + "</span></li>"; } } infoTextEmp += "</ul>"; infoTextJob += "</ul>"; var markerTmp = new google.maps.Marker({ position: cluster.getCenter(), draggable: false }); if (showJob) { mapGlobals.infoBubble.addTab('<?php echo $locale_text["GPSMAP_job_list"]; ?> ', infoTextJob); } if (showEmp) { mapGlobals.infoBubble.addTab('<?php echo $locale_text["GPSMAP_employees"]; ?> ', infoTextEmp); } mapGlobals.infoBubble.open(mapGlobals.map, markerTmp); }); getCarlocations("**FIRST**"); //call getCarlocations runs every 60 sec setTimeout(() => { getCarlocations("**LATEST**"); setInterval(() => getCarlocations("**LATEST**"), 60000); }, 60000); } </script> </body> </html>